diff mbox

, PR target/68404, Fix PowerPC fusion error

Message ID 20160209174938.GA17309@ibm-tiger.the-meissners.org
State New
Headers show

Commit Message

Michael Meissner Feb. 9, 2016, 5:49 p.m. UTC
This bug fixes PR 68404, which created an insn for the fusion operation when
accessing an array with a large constant offset that the downstream passes
(regrenam in particular don't like).  Because fusion in general adds so little
to the performance of power8, I just eliminated the compiler from generating
this case for GCC 6.  In the GCC 7 timeframe, I likely will revist fusion for
power9 support.  I ran a spec 2006 benchmark suite comparing the current
behavior and the fix for PR 68404, and it was in the noise level (mcf was 1%
slower, others ranged from 0.3% slower to 0.4% faster).

I did a bootstrap build, including a bootstrap profiled build with LTO (which
is how the problem was found) and it was found.  I rewrote 2 of the 3 fusion
tests so that it uses fusion from a medium code toc entry instead of accessing
an array element with a constant index over 65536 bytes.

Is this patch ok to apply?  If you would prefer, I can eliminate the code
inside of the fusion_gpr_addis predicate instead of using #if 0.

[gcc]
2016-02-08  Michael Meissner  <meissner@linux.vnet.ibm.com>

	PR target/68404
	* config/rs6000/predicates.md (fusion_gpr_addis): Prevent fusing
	an ADDIS that adds a pointer to a large constant that sets the
	upper16 bits with a load operation.

[gcc/testsuite]
2016-02-08  Michael Meissner  <meissner@linux.vnet.ibm.com>

	PR target/68404
	* gcc.target/powerpc/fusion.c: Rewrite test to use TOC fusion
	instead accessing a really large arrray.
	* gcc.target/powerpc/fusion3.c: Likewise.

Comments

David Edelsohn Feb. 9, 2016, 9:20 p.m. UTC | #1
On Tue, Feb 9, 2016 at 9:49 AM, Michael Meissner
<meissner@linux.vnet.ibm.com> wrote:
> This bug fixes PR 68404, which created an insn for the fusion operation when
> accessing an array with a large constant offset that the downstream passes
> (regrenam in particular don't like).  Because fusion in general adds so little
> to the performance of power8, I just eliminated the compiler from generating
> this case for GCC 6.  In the GCC 7 timeframe, I likely will revist fusion for
> power9 support.  I ran a spec 2006 benchmark suite comparing the current
> behavior and the fix for PR 68404, and it was in the noise level (mcf was 1%
> slower, others ranged from 0.3% slower to 0.4% faster).
>
> I did a bootstrap build, including a bootstrap profiled build with LTO (which
> is how the problem was found) and it was found.  I rewrote 2 of the 3 fusion
> tests so that it uses fusion from a medium code toc entry instead of accessing
> an array element with a constant index over 65536 bytes.
>
> Is this patch ok to apply?  If you would prefer, I can eliminate the code
> inside of the fusion_gpr_addis predicate instead of using #if 0.
>
> [gcc]
> 2016-02-08  Michael Meissner  <meissner@linux.vnet.ibm.com>
>
>         PR target/68404
>         * config/rs6000/predicates.md (fusion_gpr_addis): Prevent fusing
>         an ADDIS that adds a pointer to a large constant that sets the
>         upper16 bits with a load operation.
>
> [gcc/testsuite]
> 2016-02-08  Michael Meissner  <meissner@linux.vnet.ibm.com>
>
>         PR target/68404
>         * gcc.target/powerpc/fusion.c: Rewrite test to use TOC fusion
>         instead accessing a really large arrray.
>         * gcc.target/powerpc/fusion3.c: Likewise.

Please remove the code entirely, not #if 0.

Okay with that change.

Thanks, David
diff mbox

Patch

Index: gcc/config/rs6000/predicates.md
===================================================================
--- gcc/config/rs6000/predicates.md	(revision 233220)
+++ gcc/config/rs6000/predicates.md	(working copy)
@@ -1716,10 +1716,17 @@  (define_predicate "fusion_gpr_addis"
   if (CONST_INT_P (op))
     int_const = op;
 
+#if 0
+  /* PR 68404 -- regrename doesn't  like:
+
+	(mem (plus (plus (reg)
+			 (const_int))
+		   (const_int))))  */
   else if (GET_CODE (op) == PLUS
 	   && base_reg_operand (XEXP (op, 0), Pmode)
 	   && CONST_INT_P (XEXP (op, 1)))
     int_const = XEXP (op, 1);
+#endif
 
   else
     return 0;
Index: gcc/testsuite/gcc.target/powerpc/fusion3.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/fusion3.c	(revision 233220)
+++ gcc/testsuite/gcc.target/powerpc/fusion3.c	(working copy)
@@ -4,15 +4,24 @@ 
 /* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */
 /* { dg-options "-mcpu=power7 -mtune=power9 -O3" } */
 
-#define LARGE 0x12345
+#define SIZE 4
+struct foo {
+  float f;
+  double d;
+};
 
-int fusion_float_read (float *p){ return p[LARGE]; }
-int fusion_double_read (double *p){ return p[LARGE]; }
+static struct foo st[SIZE];
+struct foo *ptr_st = &st[0];
 
-void fusion_float_write (float *p, float f){ p[LARGE] = f; }
-void fusion_double_write (double *p, double d){ p[LARGE] = d; }
+float fusion_float_read (void){ return st[SIZE].f; }
+double fusion_float_extend (void){ return (double)st[SIZE].f; }
+double fusion_double_read (void){ return st[SIZE].d; }
 
-/* { dg-final { scan-assembler "load fusion, type SF"  } } */
-/* { dg-final { scan-assembler "load fusion, type DF"  } } */
-/* { dg-final { scan-assembler "store fusion, type SF" } } */
-/* { dg-final { scan-assembler "store fusion, type DF" } } */
+void fusion_float_write (float f){ st[SIZE].f = f; }
+void fusion_float_truncate (double d){ st[SIZE].f = (float)d; }
+void fusion_double_write (double d){ st[SIZE].d = d; }
+
+/* { dg-final { scan-assembler-times "load fusion, type SF"  2 } } */
+/* { dg-final { scan-assembler-times "load fusion, type DF"  1 } } */
+/* { dg-final { scan-assembler-times "store fusion, type SF" 2 } } */
+/* { dg-final { scan-assembler-times "store fusion, type DF" 1 } } */
Index: gcc/testsuite/gcc.target/powerpc/fusion.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/fusion.c	(revision 233220)
+++ gcc/testsuite/gcc.target/powerpc/fusion.c	(working copy)
@@ -1,17 +1,28 @@ 
-/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
 /* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
 /* { dg-require-effective-target powerpc_p8vector_ok } */
 /* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */
-/* { dg-options "-mcpu=power7 -mtune=power8 -O3" } */
+/* { dg-options "-mcpu=power7 -mtune=power8 -O3 -mcmodel=medium" } */
 
-#define LARGE 0x12345
+#define SIZE 4
+struct foo {
+  unsigned char uc;
+  signed char sc;
+  unsigned short us;
+  short ss;
+  int i;
+  unsigned u;
+};
 
-int fusion_uchar (unsigned char *p){ return p[LARGE]; }
-int fusion_schar (signed char *p){ return p[LARGE]; }
-int fusion_ushort (unsigned short *p){ return p[LARGE]; }
-int fusion_short (short *p){ return p[LARGE]; }
-int fusion_int (int *p){ return p[LARGE]; }
-unsigned fusion_uns (unsigned *p){ return p[LARGE]; }
+static struct foo st[SIZE];
+struct foo *ptr_st = &st[0];
+
+int fusion_uchar (void){ return st[SIZE-1].uc; }
+int fusion_schar (void){ return st[SIZE-1].sc; }
+int fusion_ushort (void){ return st[SIZE-1].us; }
+int fusion_short (void){ return st[SIZE-1].ss; }
+int fusion_int (void){ return st[SIZE-1].i; }
+unsigned fusion_uns (void){ return st[SIZE-1].u; }
 
 /* { dg-final { scan-assembler-times "gpr load fusion"    6 } } */
 /* { dg-final { scan-assembler-times "lbz"                2 } } */