diff mbox

Simplify a VEC_SELECT fed by its own inverse

Message ID 1398111582.659.3.camel@gnopaine
State New
Headers show

Commit Message

Bill Schmidt April 21, 2014, 8:19 p.m. UTC
Hi,

Here's a revised patch in response to Marc's comments.  Again,
bootstrapped and tested on powerpc64[,le]-unknown-linux-gnu.  Is this ok
for trunk?

Thanks,
Bill


[gcc]

2014-04-21  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

	* simplify-rtx.c (simplify_binary_operation_1): Optimize case of
	nested VEC_SELECTs that are inverses of each other.

[gcc/testsuite]

2014-04-21  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

	* gcc.target/powerpc/vsxcopy.c: New test.

Comments

Richard Henderson April 21, 2014, 8:48 p.m. UTC | #1
On 04/21/2014 01:19 PM, Bill Schmidt wrote:
> +      if (GET_CODE (trueop0) == VEC_SELECT
> +	  && GET_MODE (XEXP (trueop0, 0)) == mode)
> +	{
> +	  rtx op0_subop1 = XEXP (trueop0, 1);
> +	  gcc_assert (GET_CODE (op0_subop1) == PARALLEL);
> +	  gcc_assert (XVECLEN (trueop1, 0) == GET_MODE_NUNITS (mode));
> +
> +	  /* Apply the outer ordering vector to the inner one.  (The inner
> +	     ordering vector is expressly permitted to be of a different
> +	     length than the outer one.)  If the result is { 0, 1, ..., n-1 }
> +	     then the two VEC_SELECTs cancel.  */
> +	  for (int i = 0; i < XVECLEN (trueop1, 0); ++i)
> +	    {
> +	      rtx x = XVECEXP (trueop1, 0, i);
> +	      gcc_assert (CONST_INT_P (x));
> +	      rtx y = XVECEXP (op0_subop1, 0, INTVAL (x));
> +	      gcc_assert (CONST_INT_P (y));

In two places you're asserting that you've got a constant permutation.  Surely
there should be a non-assertion check and graceful exit for either select to be
a variable permutation.


r~
Bill Schmidt April 22, 2014, 2:45 a.m. UTC | #2
On Mon, 2014-04-21 at 13:48 -0700, Richard Henderson wrote:
> On 04/21/2014 01:19 PM, Bill Schmidt wrote:
> > +      if (GET_CODE (trueop0) == VEC_SELECT
> > +	  && GET_MODE (XEXP (trueop0, 0)) == mode)
> > +	{
> > +	  rtx op0_subop1 = XEXP (trueop0, 1);
> > +	  gcc_assert (GET_CODE (op0_subop1) == PARALLEL);
> > +	  gcc_assert (XVECLEN (trueop1, 0) == GET_MODE_NUNITS (mode));
> > +
> > +	  /* Apply the outer ordering vector to the inner one.  (The inner
> > +	     ordering vector is expressly permitted to be of a different
> > +	     length than the outer one.)  If the result is { 0, 1, ..., n-1 }
> > +	     then the two VEC_SELECTs cancel.  */
> > +	  for (int i = 0; i < XVECLEN (trueop1, 0); ++i)
> > +	    {
> > +	      rtx x = XVECEXP (trueop1, 0, i);
> > +	      gcc_assert (CONST_INT_P (x));
> > +	      rtx y = XVECEXP (op0_subop1, 0, INTVAL (x));
> > +	      gcc_assert (CONST_INT_P (y));
> 
> In two places you're asserting that you've got a constant permutation.  Surely
> there should be a non-assertion check and graceful exit for either select to be
> a variable permutation.

Ah.  I was not aware this was even a possibility.  From rtl.def:

/* Describes an operation that selects parts of a vector.                       
   Operands 0 is the source vector, operand 1 is a PARALLEL that contains       
   a CONST_INT for each of the subparts of the result vector, giving the        
   number of the source subpart that should be stored into it.  */              
DEF_RTL_EXPR(VEC_SELECT, "vec_select", "ee", RTX_BIN_ARITH)                     

If variable permutations are possible with VEC_SELECT, then I suppose
this commentary should be updated.  The GCC internals document contains
similar text in section 13.12.

I'll rebuild the patch per your comments tomorrow.  Thanks for letting
me know about this!

Regards,
Bill

> 
> 
> r~
>
Marc Glisse April 22, 2014, 6:59 a.m. UTC | #3
On Mon, 21 Apr 2014, Richard Henderson wrote:

> On 04/21/2014 01:19 PM, Bill Schmidt wrote:
>> +      if (GET_CODE (trueop0) == VEC_SELECT
>> +	  && GET_MODE (XEXP (trueop0, 0)) == mode)
>> +	{
>> +	  rtx op0_subop1 = XEXP (trueop0, 1);
>> +	  gcc_assert (GET_CODE (op0_subop1) == PARALLEL);
>> +	  gcc_assert (XVECLEN (trueop1, 0) == GET_MODE_NUNITS (mode));
>> +
>> +	  /* Apply the outer ordering vector to the inner one.  (The inner
>> +	     ordering vector is expressly permitted to be of a different
>> +	     length than the outer one.)  If the result is { 0, 1, ..., n-1 }
>> +	     then the two VEC_SELECTs cancel.  */
>> +	  for (int i = 0; i < XVECLEN (trueop1, 0); ++i)
>> +	    {
>> +	      rtx x = XVECEXP (trueop1, 0, i);
>> +	      gcc_assert (CONST_INT_P (x));
>> +	      rtx y = XVECEXP (op0_subop1, 0, INTVAL (x));
>> +	      gcc_assert (CONST_INT_P (y));
>
> In two places you're asserting that you've got a constant permutation.  Surely
> there should be a non-assertion check and graceful exit for either select to be
> a variable permutation.

Note that in the case where trueop0 is a CONST_VECTOR, we already check 
each element of trueop1:

                   gcc_assert (CONST_INT_P (x));

In the case where the result is a scalar, we also have:

           gcc_assert (CONST_INT_P (XVECEXP (trueop1, 0, 0)));

so we will have other issues if something ever creates a variable 
vec_select. Not that a graceful exit will hurt of course.
Richard Sandiford April 22, 2014, 8:24 a.m. UTC | #4
Marc Glisse <marc.glisse@inria.fr> writes:
> On Mon, 21 Apr 2014, Richard Henderson wrote:
>
>> On 04/21/2014 01:19 PM, Bill Schmidt wrote:
>>> +      if (GET_CODE (trueop0) == VEC_SELECT
>>> +	  && GET_MODE (XEXP (trueop0, 0)) == mode)
>>> +	{
>>> +	  rtx op0_subop1 = XEXP (trueop0, 1);
>>> +	  gcc_assert (GET_CODE (op0_subop1) == PARALLEL);
>>> +	  gcc_assert (XVECLEN (trueop1, 0) == GET_MODE_NUNITS (mode));
>>> +
>>> +	  /* Apply the outer ordering vector to the inner one.  (The inner
>>> +	     ordering vector is expressly permitted to be of a different
>>> +	     length than the outer one.)  If the result is { 0, 1, ..., n-1 }
>>> +	     then the two VEC_SELECTs cancel.  */
>>> +	  for (int i = 0; i < XVECLEN (trueop1, 0); ++i)
>>> +	    {
>>> +	      rtx x = XVECEXP (trueop1, 0, i);
>>> +	      gcc_assert (CONST_INT_P (x));
>>> +	      rtx y = XVECEXP (op0_subop1, 0, INTVAL (x));
>>> +	      gcc_assert (CONST_INT_P (y));
>>
>> In two places you're asserting that you've got a constant permutation.  Surely
>> there should be a non-assertion check and graceful exit for either
>> select to be
>> a variable permutation.
>
> Note that in the case where trueop0 is a CONST_VECTOR, we already check 
> each element of trueop1:
>
>                    gcc_assert (CONST_INT_P (x));
>
> In the case where the result is a scalar, we also have:
>
>            gcc_assert (CONST_INT_P (XVECEXP (trueop1, 0, 0)));
>
> so we will have other issues if something ever creates a variable 
> vec_select. Not that a graceful exit will hurt of course.

I realise this isn't the point, but maybe we should go easy on this kind
of gcc_assert.  Using INTVAL is itself an assertion that you have a
CONST_INT.  Adding gcc_asserts on top (and so forcing the assert even
in release compilers) kind-of subverts the --enable-checking option.

Thanks,
Richard
diff mbox

Patch

Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	(revision 209516)
+++ gcc/simplify-rtx.c	(working copy)
@@ -3673,6 +3673,31 @@  simplify_binary_operation_1 (enum rtx_code code, e
 	    }
 	}
 
+      /* If we have two nested selects that are inverses of each
+	 other, replace them with the source operand.  */
+      if (GET_CODE (trueop0) == VEC_SELECT
+	  && GET_MODE (XEXP (trueop0, 0)) == mode)
+	{
+	  rtx op0_subop1 = XEXP (trueop0, 1);
+	  gcc_assert (GET_CODE (op0_subop1) == PARALLEL);
+	  gcc_assert (XVECLEN (trueop1, 0) == GET_MODE_NUNITS (mode));
+
+	  /* Apply the outer ordering vector to the inner one.  (The inner
+	     ordering vector is expressly permitted to be of a different
+	     length than the outer one.)  If the result is { 0, 1, ..., n-1 }
+	     then the two VEC_SELECTs cancel.  */
+	  for (int i = 0; i < XVECLEN (trueop1, 0); ++i)
+	    {
+	      rtx x = XVECEXP (trueop1, 0, i);
+	      gcc_assert (CONST_INT_P (x));
+	      rtx y = XVECEXP (op0_subop1, 0, INTVAL (x));
+	      gcc_assert (CONST_INT_P (y));
+	      if (i != INTVAL (y))
+		return 0;
+	    }
+	  return XEXP (trueop0, 0);
+	}
+
       return 0;
     case VEC_CONCAT:
       {
Index: gcc/testsuite/gcc.target/powerpc/vsxcopy.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/vsxcopy.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/vsxcopy.c	(working copy)
@@ -0,0 +1,15 @@ 
+/* { dg-do compile { target { powerpc64*-*-* } } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O1" } */
+/* { dg-final { scan-assembler "lxvd2x" } } */
+/* { dg-final { scan-assembler "stxvd2x" } } */
+/* { dg-final { scan-assembler-not "xxpermdi" } } */
+
+typedef float vecf __attribute__ ((vector_size (16)));
+extern vecf j, k;
+
+void fun (void)
+{
+  j = k;
+}
+