diff mbox

Make vectoriser use operand_equal_p to compare base addresses

Message ID g4bp028ey3.fsf@linaro.org
State New
Headers show

Commit Message

Richard Sandiford April 19, 2011, 2:59 p.m. UTC
In the attached testcase, we treat:

    sum += x[i][0] * x[i][0] + x[i][1] * x[i][1];

as being two independent strided loads: x[i][0] and x[i][1].
On targets with appropriate support, we therefore use two interleaved
loads rather than one, then discard one half of each result.
This does not happen if bar() is compiled on its own.

The code before vectorisation looks like this:

<bb 3>:
  i.0_5 = (unsigned int) i_32;
  D.3532_6 = i.0_5 * 320;
  D.3533_8 = x_7(D) + D.3532_6;

<bb 4>:
  i.1_14 = (unsigned int) i_34;
  D.3559_15 = i.1_14 * 8;
  D.3558_16 = D.3533_8 + D.3559_15;
  D.3557_17 = *D.3558_16[0];
  D.3555_19 = *D.3558_16[1];
  ...

The two DR_BASE_ADDRESSES are therefore the expansion of D.3558_8:

    x_7(D) + (unsigned int) i_32 * 320

which we don't think are equal.  The comment in tree-data-refs.h
made me think that (unsigned int) i_32 * 320 ought really to be
in the DR_OFFSET, but that only seems to apply to offsets that
occur in the memory reference itself.

Fixed by using operand_equal_p to compare base addresses.
Tested on x86_64-linux-gnu and arm-linux-gnueabi.  OK to install?

I've not made the test dependent on a target selector because
it seemed like the message should be printed regardless.

Richard


gcc/
	* tree-vect-data-refs.c (vect_drs_dependent_in_basic_block): Use
	operand_equal_p to compare DR_BASE_ADDRESSes.
	(vect_check_interleaving): Likewise.

gcc/testsuite/
	* gcc.dg/vect/vect-119.c: New test.

Comments

Richard Biener April 19, 2011, 3:02 p.m. UTC | #1
On Tue, Apr 19, 2011 at 4:59 PM, Richard Sandiford
<richard.sandiford@linaro.org> wrote:
> In the attached testcase, we treat:
>
>    sum += x[i][0] * x[i][0] + x[i][1] * x[i][1];
>
> as being two independent strided loads: x[i][0] and x[i][1].
> On targets with appropriate support, we therefore use two interleaved
> loads rather than one, then discard one half of each result.
> This does not happen if bar() is compiled on its own.
>
> The code before vectorisation looks like this:
>
> <bb 3>:
>  i.0_5 = (unsigned int) i_32;
>  D.3532_6 = i.0_5 * 320;
>  D.3533_8 = x_7(D) + D.3532_6;
>
> <bb 4>:
>  i.1_14 = (unsigned int) i_34;
>  D.3559_15 = i.1_14 * 8;
>  D.3558_16 = D.3533_8 + D.3559_15;
>  D.3557_17 = *D.3558_16[0];
>  D.3555_19 = *D.3558_16[1];
>  ...
>
> The two DR_BASE_ADDRESSES are therefore the expansion of D.3558_8:
>
>    x_7(D) + (unsigned int) i_32 * 320
>
> which we don't think are equal.  The comment in tree-data-refs.h
> made me think that (unsigned int) i_32 * 320 ought really to be
> in the DR_OFFSET, but that only seems to apply to offsets that
> occur in the memory reference itself.
>
> Fixed by using operand_equal_p to compare base addresses.
> Tested on x86_64-linux-gnu and arm-linux-gnueabi.  OK to install?
>
> I've not made the test dependent on a target selector because
> it seemed like the message should be printed regardless.

Ok.

Thanks,
Richard.

> Richard
>
>
> gcc/
>        * tree-vect-data-refs.c (vect_drs_dependent_in_basic_block): Use
>        operand_equal_p to compare DR_BASE_ADDRESSes.
>        (vect_check_interleaving): Likewise.
>
> gcc/testsuite/
>        * gcc.dg/vect/vect-119.c: New test.
>
> Index: gcc/tree-vect-data-refs.c
> ===================================================================
> --- gcc/tree-vect-data-refs.c   2011-04-19 14:59:58.000000000 +0100
> +++ gcc/tree-vect-data-refs.c   2011-04-19 14:59:58.000000000 +0100
> @@ -353,11 +353,7 @@ vect_drs_dependent_in_basic_block (struc
>
>   /* Check that the data-refs have same bases and offsets.  If not, we can't
>      determine if they are dependent.  */
> -  if ((DR_BASE_ADDRESS (dra) != DR_BASE_ADDRESS (drb)
> -       && (TREE_CODE (DR_BASE_ADDRESS (dra)) != ADDR_EXPR
> -           || TREE_CODE (DR_BASE_ADDRESS (drb)) != ADDR_EXPR
> -           || TREE_OPERAND (DR_BASE_ADDRESS (dra), 0)
> -           != TREE_OPERAND (DR_BASE_ADDRESS (drb),0)))
> +  if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0)
>       || !dr_equal_offsets_p (dra, drb))
>     return true;
>
> @@ -403,11 +399,7 @@ vect_check_interleaving (struct data_ref
>
>   /* Check that the data-refs have same first location (except init) and they
>      are both either store or load (not load and store).  */
> -  if ((DR_BASE_ADDRESS (dra) != DR_BASE_ADDRESS (drb)
> -       && (TREE_CODE (DR_BASE_ADDRESS (dra)) != ADDR_EXPR
> -          || TREE_CODE (DR_BASE_ADDRESS (drb)) != ADDR_EXPR
> -          || TREE_OPERAND (DR_BASE_ADDRESS (dra), 0)
> -          != TREE_OPERAND (DR_BASE_ADDRESS (drb),0)))
> +  if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0)
>       || !dr_equal_offsets_p (dra, drb)
>       || !tree_int_cst_compare (DR_INIT (dra), DR_INIT (drb))
>       || DR_IS_READ (dra) != DR_IS_READ (drb))
> Index: gcc/testsuite/gcc.dg/vect/vect-119.c
> ===================================================================
> --- /dev/null   2011-03-23 08:42:11.268792848 +0000
> +++ gcc/testsuite/gcc.dg/vect/vect-119.c        2011-04-19 14:59:58.000000000 +0100
> @@ -0,0 +1,28 @@
> +/* { dg-do compile } */
> +
> +#define OUTER 32
> +#define INNER 40
> +
> +static unsigned int
> +bar (const unsigned int x[INNER][2], unsigned int sum)
> +{
> +  int i;
> +
> +  for (i = 0; i < INNER; i++)
> +    sum += x[i][0] * x[i][0] + x[i][1] * x[i][1];
> +  return sum;
> +}
> +
> +unsigned int foo (const unsigned int x[OUTER][INNER][2])
> +{
> +  int i;
> +  unsigned int sum;
> +
> +  sum = 0.0f;
> +  for (i = 0; i < OUTER; i++)
> +    sum = bar (x[i], sum);
> +  return sum;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "Detected interleaving of size 2" 1 "vect" } } */
> +/* { dg-final { cleanup-tree-dump "vect" } } */
>
H.J. Lu May 16, 2012, 4:55 a.m. UTC | #2
On Tue, Apr 19, 2011 at 7:59 AM, Richard Sandiford
<richard.sandiford@linaro.org> wrote:
> In the attached testcase, we treat:
>
>    sum += x[i][0] * x[i][0] + x[i][1] * x[i][1];
>
> as being two independent strided loads: x[i][0] and x[i][1].
> On targets with appropriate support, we therefore use two interleaved
> loads rather than one, then discard one half of each result.
> This does not happen if bar() is compiled on its own.
>
> The code before vectorisation looks like this:
>
> <bb 3>:
>  i.0_5 = (unsigned int) i_32;
>  D.3532_6 = i.0_5 * 320;
>  D.3533_8 = x_7(D) + D.3532_6;
>
> <bb 4>:
>  i.1_14 = (unsigned int) i_34;
>  D.3559_15 = i.1_14 * 8;
>  D.3558_16 = D.3533_8 + D.3559_15;
>  D.3557_17 = *D.3558_16[0];
>  D.3555_19 = *D.3558_16[1];
>  ...
>
> The two DR_BASE_ADDRESSES are therefore the expansion of D.3558_8:
>
>    x_7(D) + (unsigned int) i_32 * 320
>
> which we don't think are equal.  The comment in tree-data-refs.h
> made me think that (unsigned int) i_32 * 320 ought really to be
> in the DR_OFFSET, but that only seems to apply to offsets that
> occur in the memory reference itself.
>
> Fixed by using operand_equal_p to compare base addresses.
> Tested on x86_64-linux-gnu and arm-linux-gnueabi.  OK to install?
>
> I've not made the test dependent on a target selector because
> it seemed like the message should be printed regardless.
>
> Richard
>
>
> gcc/
>        * tree-vect-data-refs.c (vect_drs_dependent_in_basic_block): Use
>        operand_equal_p to compare DR_BASE_ADDRESSes.
>        (vect_check_interleaving): Likewise.
>

This caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53366
diff mbox

Patch

Index: gcc/tree-vect-data-refs.c
===================================================================
--- gcc/tree-vect-data-refs.c	2011-04-19 14:59:58.000000000 +0100
+++ gcc/tree-vect-data-refs.c	2011-04-19 14:59:58.000000000 +0100
@@ -353,11 +353,7 @@  vect_drs_dependent_in_basic_block (struc
 
   /* Check that the data-refs have same bases and offsets.  If not, we can't
      determine if they are dependent.  */
-  if ((DR_BASE_ADDRESS (dra) != DR_BASE_ADDRESS (drb)
-       && (TREE_CODE (DR_BASE_ADDRESS (dra)) != ADDR_EXPR
-           || TREE_CODE (DR_BASE_ADDRESS (drb)) != ADDR_EXPR
-           || TREE_OPERAND (DR_BASE_ADDRESS (dra), 0)
-           != TREE_OPERAND (DR_BASE_ADDRESS (drb),0)))
+  if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0)
       || !dr_equal_offsets_p (dra, drb))
     return true;
 
@@ -403,11 +399,7 @@  vect_check_interleaving (struct data_ref
 
   /* Check that the data-refs have same first location (except init) and they
      are both either store or load (not load and store).  */
-  if ((DR_BASE_ADDRESS (dra) != DR_BASE_ADDRESS (drb)
-       && (TREE_CODE (DR_BASE_ADDRESS (dra)) != ADDR_EXPR
-	   || TREE_CODE (DR_BASE_ADDRESS (drb)) != ADDR_EXPR
-	   || TREE_OPERAND (DR_BASE_ADDRESS (dra), 0)
-	   != TREE_OPERAND (DR_BASE_ADDRESS (drb),0)))
+  if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0)
       || !dr_equal_offsets_p (dra, drb)
       || !tree_int_cst_compare (DR_INIT (dra), DR_INIT (drb))
       || DR_IS_READ (dra) != DR_IS_READ (drb))
Index: gcc/testsuite/gcc.dg/vect/vect-119.c
===================================================================
--- /dev/null	2011-03-23 08:42:11.268792848 +0000
+++ gcc/testsuite/gcc.dg/vect/vect-119.c	2011-04-19 14:59:58.000000000 +0100
@@ -0,0 +1,28 @@ 
+/* { dg-do compile } */
+
+#define OUTER 32
+#define INNER 40
+
+static unsigned int
+bar (const unsigned int x[INNER][2], unsigned int sum)
+{
+  int i;
+
+  for (i = 0; i < INNER; i++)
+    sum += x[i][0] * x[i][0] + x[i][1] * x[i][1];
+  return sum;
+}
+
+unsigned int foo (const unsigned int x[OUTER][INNER][2])
+{
+  int i;
+  unsigned int sum;
+
+  sum = 0.0f;
+  for (i = 0; i < OUTER; i++)
+    sum = bar (x[i], sum);
+  return sum;
+}
+
+/* { dg-final { scan-tree-dump-times "Detected interleaving of size 2" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */