Patchwork real_zerop for vectors

login
register
mail settings
Submitter Marc Glisse
Date Oct. 28, 2012, 3:14 p.m.
Message ID <alpine.DEB.2.02.1210281554180.4597@stedding.saclay.inria.fr>
Download mbox | patch
Permalink /patch/194710/
State New
Headers show

Comments

Marc Glisse - Oct. 28, 2012, 3:14 p.m.
Hello,

this patch lets some predicates on floating point constants answer true 
for vectors, so optimizations are applied.

Tested bootstrap + testsuite (default languages).

2012-10-29  Marc Glisse  <marc.glisse@inria.fr>

 	PR middle-end/55027

gcc/
 	* tree.c (real_zerop, real_onep, real_twop, real_minus_onep):
 	Handle VECTOR_CST.

testsuite/
 	* gcc.dg/pr55027.c: New testcase.
Paolo Carlini - Oct. 28, 2012, 3:46 p.m.
On 10/28/2012 04:14 PM, Marc Glisse wrote:
> Hello,
>
> this patch lets some predicates on floating point constants answer 
> true for vectors, so optimizations are applied.
Great.

I wonder how are we doing lately in terms of function pointer inlining?! 
If the current optimizers can already able to smoothly inline real_zerop 
& co we could have a single helper function and avoid all this 
redundancy... In case, I suppose other code could also benefit.

Thanks,
Paolo.
Paolo Carlini - Oct. 28, 2012, 3:54 p.m.
On 10/28/2012 04:46 PM, Paolo Carlini wrote:
> On 10/28/2012 04:14 PM, Marc Glisse wrote:
>> Hello,
>>
>> this patch lets some predicates on floating point constants answer 
>> true for vectors, so optimizations are applied.
> Great.
>
> I wonder how are we doing lately in terms of function pointer 
> inlining?! If the current optimizers can already able to smoothly 
> inline real_zerop & co we could have a single helper function and 
> avoid all this redundancy... In case, I suppose other code could also 
> benefit.
Uhm, sorry, I didn't notice the functions are recursive. The situation 
seems hopeless, too bad.

Paolo.
Marc Glisse - Oct. 28, 2012, 4:34 p.m.
On Sun, 28 Oct 2012, Paolo Carlini wrote:

> On 10/28/2012 04:46 PM, Paolo Carlini wrote:
>> On 10/28/2012 04:14 PM, Marc Glisse wrote:
>>> Hello,
>>> 
>>> this patch lets some predicates on floating point constants answer true 
>>> for vectors, so optimizations are applied.
>> Great.
>> 
>> I wonder how are we doing lately in terms of function pointer inlining?! If 
>> the current optimizers can already able to smoothly inline real_zerop & co

Inlining real_zerop can only happen in lto builds.

>> we could have a single helper function and avoid all this redundancy... In 
>> case, I suppose other code could also benefit.
> Uhm, sorry, I didn't notice the functions are recursive. The situation seems 
> hopeless, too bad.

The recursion has a bounded depth of 2 ;-)

It is true that we could have a single function in tree.c:
bool real_intcstp (const_tree, int);

with possible trivial wrappers in tree.h.
Marc Glisse - Oct. 28, 2012, 4:51 p.m.
On Sun, 28 Oct 2012, Marc Glisse wrote:

[there are 4 real_*p that only differ by 1 character]

> It is true that we could have a single function in tree.c:
> bool real_intcstp (const_tree, int);

The helper function could even take a REAL_VALUE_TYPE as second 
argument, so the non-inline part doesn't have more work than currently.

Trying to also merge the real_*p predicates with the integer_*p predicates 
seems harder (in fancy C++, we'd have a number of ways of writing the code 
for complex and vectors only once, but I don't think we want to go there).

> with possible trivial wrappers in tree.h.
Richard Guenther - Oct. 29, 2012, 2:05 p.m.
On Sun, Oct 28, 2012 at 4:14 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
> Hello,
>
> this patch lets some predicates on floating point constants answer true for
> vectors, so optimizations are applied.
>
> Tested bootstrap + testsuite (default languages).

Ok.  Bonus points if you quickly eyed users of whether they may be surprised
in vectors coming through now.

Thanks,
Richard.

> 2012-10-29  Marc Glisse  <marc.glisse@inria.fr>
>
>         PR middle-end/55027
>
> gcc/
>         * tree.c (real_zerop, real_onep, real_twop, real_minus_onep):
>         Handle VECTOR_CST.
>
> testsuite/
>         * gcc.dg/pr55027.c: New testcase.
>
> --
> Marc Glisse
> Index: gcc/testsuite/gcc.dg/pr55027.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/pr55027.c      (revision 0)
> +++ gcc/testsuite/gcc.dg/pr55027.c      (revision 0)
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Ofast -fdump-tree-optimized-raw" } */
> +
> +typedef double v2df __attribute__ ((__vector_size__ (2 * sizeof
> (double))));
> +
> +void f (v2df *x)
> +{
> +  *x = 0 + 1 * *x;
> +}
> +
> +/* { dg-final { scan-tree-dump-not "gimple_assign" "optimized" } } */
> +/* { dg-final { cleanup-tree-dump "optimized" } } */
>
> Property changes on: gcc/testsuite/gcc.dg/pr55027.c
> ___________________________________________________________________
> Added: svn:keywords
>    + Author Date Id Revision URL
> Added: svn:eol-style
>    + native
>
> Index: gcc/tree.c
> ===================================================================
> --- gcc/tree.c  (revision 192894)
> +++ gcc/tree.c  (working copy)
> @@ -1985,75 +1985,127 @@ tree_floor_log2 (const_tree expr)
>  }
>
>  /* Return 1 if EXPR is the real constant zero.  Trailing zeroes matter for
>     decimal float constants, so don't return 1 for them.  */
>
>  int
>  real_zerop (const_tree expr)
>  {
>    STRIP_NOPS (expr);
>
> -  return ((TREE_CODE (expr) == REAL_CST
> -          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0)
> -          && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))
> -         || (TREE_CODE (expr) == COMPLEX_CST
> -             && real_zerop (TREE_REALPART (expr))
> -             && real_zerop (TREE_IMAGPART (expr))));
> +  switch (TREE_CODE (expr))
> +    {
> +    case REAL_CST:
> +      return REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0)
> +            && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr))));
> +    case COMPLEX_CST:
> +      return real_zerop (TREE_REALPART (expr))
> +            && real_zerop (TREE_IMAGPART (expr));
> +    case VECTOR_CST:
> +      {
> +       unsigned i;
> +       for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)
> +         if (!real_zerop (VECTOR_CST_ELT (expr, i)))
> +           return false;
> +       return true;
> +      }
> +    default:
> +      return false;
> +    }
>  }
>
>  /* Return 1 if EXPR is the real constant one in real or complex form.
>     Trailing zeroes matter for decimal float constants, so don't return
>     1 for them.  */
>
>  int
>  real_onep (const_tree expr)
>  {
>    STRIP_NOPS (expr);
>
> -  return ((TREE_CODE (expr) == REAL_CST
> -          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1)
> -          && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))
> -         || (TREE_CODE (expr) == COMPLEX_CST
> -             && real_onep (TREE_REALPART (expr))
> -             && real_zerop (TREE_IMAGPART (expr))));
> +  switch (TREE_CODE (expr))
> +    {
> +    case REAL_CST:
> +      return REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1)
> +            && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr))));
> +    case COMPLEX_CST:
> +      return real_onep (TREE_REALPART (expr))
> +            && real_zerop (TREE_IMAGPART (expr));
> +    case VECTOR_CST:
> +      {
> +       unsigned i;
> +       for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)
> +         if (!real_onep (VECTOR_CST_ELT (expr, i)))
> +           return false;
> +       return true;
> +      }
> +    default:
> +      return false;
> +    }
>  }
>
>  /* Return 1 if EXPR is the real constant two.  Trailing zeroes matter
>     for decimal float constants, so don't return 1 for them.  */
>
>  int
>  real_twop (const_tree expr)
>  {
>    STRIP_NOPS (expr);
>
> -  return ((TREE_CODE (expr) == REAL_CST
> -          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2)
> -          && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))
> -         || (TREE_CODE (expr) == COMPLEX_CST
> -             && real_twop (TREE_REALPART (expr))
> -             && real_zerop (TREE_IMAGPART (expr))));
> +  switch (TREE_CODE (expr))
> +    {
> +    case REAL_CST:
> +      return REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2)
> +            && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr))));
> +    case COMPLEX_CST:
> +      return real_twop (TREE_REALPART (expr))
> +            && real_zerop (TREE_IMAGPART (expr));
> +    case VECTOR_CST:
> +      {
> +       unsigned i;
> +       for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)
> +         if (!real_twop (VECTOR_CST_ELT (expr, i)))
> +           return false;
> +       return true;
> +      }
> +    default:
> +      return false;
> +    }
>  }
>
>  /* Return 1 if EXPR is the real constant minus one.  Trailing zeroes
>     matter for decimal float constants, so don't return 1 for them.  */
>
>  int
>  real_minus_onep (const_tree expr)
>  {
>    STRIP_NOPS (expr);
>
> -  return ((TREE_CODE (expr) == REAL_CST
> -          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1)
> -          && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))
> -         || (TREE_CODE (expr) == COMPLEX_CST
> -             && real_minus_onep (TREE_REALPART (expr))
> -             && real_zerop (TREE_IMAGPART (expr))));
> +  switch (TREE_CODE (expr))
> +    {
> +    case REAL_CST:
> +      return REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1)
> +            && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr))));
> +    case COMPLEX_CST:
> +      return real_minus_onep (TREE_REALPART (expr))
> +            && real_zerop (TREE_IMAGPART (expr));
> +    case VECTOR_CST:
> +      {
> +       unsigned i;
> +       for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)
> +         if (!real_minus_onep (VECTOR_CST_ELT (expr, i)))
> +           return false;
> +       return true;
> +      }
> +    default:
> +      return false;
> +    }
>  }
>
>  /* Nonzero if EXP is a constant or a cast of a constant.  */
>
>  int
>  really_constant_p (const_tree exp)
>  {
>    /* This is not quite the same as STRIP_NOPS.  It does more.  */
>    while (CONVERT_EXPR_P (exp)
>          || TREE_CODE (exp) == NON_LVALUE_EXPR)
>
Marc Glisse - Oct. 29, 2012, 2:37 p.m.
On Mon, 29 Oct 2012, Richard Biener wrote:

> On Sun, Oct 28, 2012 at 4:14 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
>> Hello,
>>
>> this patch lets some predicates on floating point constants answer true for
>> vectors, so optimizations are applied.
>>
>> Tested bootstrap + testsuite (default languages).
>
> Ok.  Bonus points if you quickly eyed users of whether they may be surprised
> in vectors coming through now.

I did (that's why I didn't also change integer_twop), but I won't claim 
the bonus points, because in fold-const.c:
* there is probably an issue with signed zero in fold_real_zero_addition_p
* the RDIV_EXPR case would like real_zerop to mean "at least one is zero"
* abs(x)>=0 or <0 doesn't seem ready

but that's not much compared to the broken integer vector optimizations 
;-)

Patch

Index: gcc/testsuite/gcc.dg/pr55027.c

===================================================================
--- gcc/testsuite/gcc.dg/pr55027.c	(revision 0)

+++ gcc/testsuite/gcc.dg/pr55027.c	(revision 0)

@@ -0,0 +1,12 @@ 

+/* { dg-do compile } */

+/* { dg-options "-Ofast -fdump-tree-optimized-raw" } */

+

+typedef double v2df __attribute__ ((__vector_size__ (2 * sizeof (double))));

+

+void f (v2df *x)

+{

+  *x = 0 + 1 * *x;

+}

+

+/* { dg-final { scan-tree-dump-not "gimple_assign" "optimized" } } */

+/* { dg-final { cleanup-tree-dump "optimized" } } */


Property changes on: gcc/testsuite/gcc.dg/pr55027.c
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision URL
Added: svn:eol-style
   + native

Index: gcc/tree.c

===================================================================
--- gcc/tree.c	(revision 192894)

+++ gcc/tree.c	(working copy)

@@ -1985,75 +1985,127 @@  tree_floor_log2 (const_tree expr)

 }
 
 /* Return 1 if EXPR is the real constant zero.  Trailing zeroes matter for
    decimal float constants, so don't return 1 for them.  */
 
 int
 real_zerop (const_tree expr)
 {
   STRIP_NOPS (expr);
 
-  return ((TREE_CODE (expr) == REAL_CST

-	   && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0)

-	   && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))

-	  || (TREE_CODE (expr) == COMPLEX_CST

-	      && real_zerop (TREE_REALPART (expr))

-	      && real_zerop (TREE_IMAGPART (expr))));

+  switch (TREE_CODE (expr))

+    {

+    case REAL_CST:

+      return REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0)

+	     && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr))));

+    case COMPLEX_CST:

+      return real_zerop (TREE_REALPART (expr))

+	     && real_zerop (TREE_IMAGPART (expr));

+    case VECTOR_CST:

+      {

+	unsigned i;

+	for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)

+	  if (!real_zerop (VECTOR_CST_ELT (expr, i)))

+	    return false;

+	return true;

+      }

+    default:

+      return false;

+    }

 }
 
 /* Return 1 if EXPR is the real constant one in real or complex form.
    Trailing zeroes matter for decimal float constants, so don't return
    1 for them.  */
 
 int
 real_onep (const_tree expr)
 {
   STRIP_NOPS (expr);
 
-  return ((TREE_CODE (expr) == REAL_CST

-	   && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1)

-	   && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))

-	  || (TREE_CODE (expr) == COMPLEX_CST

-	      && real_onep (TREE_REALPART (expr))

-	      && real_zerop (TREE_IMAGPART (expr))));

+  switch (TREE_CODE (expr))

+    {

+    case REAL_CST:

+      return REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1)

+	     && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr))));

+    case COMPLEX_CST:

+      return real_onep (TREE_REALPART (expr))

+	     && real_zerop (TREE_IMAGPART (expr));

+    case VECTOR_CST:

+      {

+	unsigned i;

+	for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)

+	  if (!real_onep (VECTOR_CST_ELT (expr, i)))

+	    return false;

+	return true;

+      }

+    default:

+      return false;

+    }

 }
 
 /* Return 1 if EXPR is the real constant two.  Trailing zeroes matter
    for decimal float constants, so don't return 1 for them.  */
 
 int
 real_twop (const_tree expr)
 {
   STRIP_NOPS (expr);
 
-  return ((TREE_CODE (expr) == REAL_CST

-	   && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2)

-	   && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))

-	  || (TREE_CODE (expr) == COMPLEX_CST

-	      && real_twop (TREE_REALPART (expr))

-	      && real_zerop (TREE_IMAGPART (expr))));

+  switch (TREE_CODE (expr))

+    {

+    case REAL_CST:

+      return REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2)

+	     && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr))));

+    case COMPLEX_CST:

+      return real_twop (TREE_REALPART (expr))

+	     && real_zerop (TREE_IMAGPART (expr));

+    case VECTOR_CST:

+      {

+	unsigned i;

+	for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)

+	  if (!real_twop (VECTOR_CST_ELT (expr, i)))

+	    return false;

+	return true;

+      }

+    default:

+      return false;

+    }

 }
 
 /* Return 1 if EXPR is the real constant minus one.  Trailing zeroes
    matter for decimal float constants, so don't return 1 for them.  */
 
 int
 real_minus_onep (const_tree expr)
 {
   STRIP_NOPS (expr);
 
-  return ((TREE_CODE (expr) == REAL_CST

-	   && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1)

-	   && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr)))))

-	  || (TREE_CODE (expr) == COMPLEX_CST

-	      && real_minus_onep (TREE_REALPART (expr))

-	      && real_zerop (TREE_IMAGPART (expr))));

+  switch (TREE_CODE (expr))

+    {

+    case REAL_CST:

+      return REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1)

+	     && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr))));

+    case COMPLEX_CST:

+      return real_minus_onep (TREE_REALPART (expr))

+	     && real_zerop (TREE_IMAGPART (expr));

+    case VECTOR_CST:

+      {

+	unsigned i;

+	for (i = 0; i < VECTOR_CST_NELTS (expr); ++i)

+	  if (!real_minus_onep (VECTOR_CST_ELT (expr, i)))

+	    return false;

+	return true;

+      }

+    default:

+      return false;

+    }

 }
 
 /* Nonzero if EXP is a constant or a cast of a constant.  */
 
 int
 really_constant_p (const_tree exp)
 {
   /* This is not quite the same as STRIP_NOPS.  It does more.  */
   while (CONVERT_EXPR_P (exp)
 	 || TREE_CODE (exp) == NON_LVALUE_EXPR)