As I was auditing rs6000.md for power9 changes, I noticed that changes I had
made in 2010 for power7 weren't as effective with power8.

The FCTIWZ/FCTIWUZ instructions convert the scalar floating point value to a
32-bit signed/unsigned integer in bits 32-63 of the floating point or vector
register.  Unfortunately, the hardware does not guarantee that bits 0-31 are
copies of the sign, so that it can be used as a valid 64-bit integer.  There is
no conversion from 32-bit int to floating point.  This meant in the power7
days, if you wanted to round a floating point value to 32-bit integer, you
would need to do:

        convert to 32-bit integer
        store 32-bit value on the stack
        load 32-bit value to a GPR
        sign/zero extend it
        store 32-bit value to the stack
        load 32-bit value to a FPR/vector register.

The optimization does a store/load to sign/zero extend, rather than going
through the GPRs.

On power8, we have a direct move instruction that copies the value between the
register sets, and the compiler will generate this if the above optimization is
turned off (which is what this patch does).

There are other ways to sign/zero extend a value in the vector registers
without doing a move using multiple instructions, but in practice direct move
seems to be as fast as the other instructions.

I bootstrapped the compiler and there were no regressions with this patch.

I rebuilt the Spec 2006 benchmark suite, and there 7 of the benchmarks that
used this sequence somewhere in the code.  I ran those benchmarks with this
patch, and compared them to the original benchmarks.  In 6 of the benchmarks,
the run time was almost precisely the same.  The 416.gamess benchmark was about
2% faster, and there were no regressions.

Is this patch ok to apply to the trunk?  I would like to apply it to the gcc 5
branch as well.  Is this ok also?

[gcc]
2016-03-11  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        PR target/70131
        * config/rs6000/rs6000.md (round32<mode>2_fprs): Do not do the
        optimization if we have direct move.
        (roundu32<mode>2_fprs): Likewise.

[gcc/testsuite]
2016-03-11  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        PR target/70131
        * gcc.target/powerpc/ppc-round2.c: New test.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md (revision 234147)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -5387,10 +5387,12 @@ (define_insn "*friz"
    xsrdpiz %x0,%x1"
   [(set_attr "type" "fp")])
 
-;; Since FCTIWZ doesn't sign extend the upper bits, we have to do a store and a
-;; load to properly sign extend the value, but at least doing a store, load
-;; into a GPR to sign extend, a store from the GPR and a load back into the FPR
-;; if we have 32-bit memory ops
+;; Opitmize converting SF/DFmode to signed SImode and back to SF/DFmode.  This
+;; optimization prevents on ISA 2.06 systems and earlier having to store the
+;; value from the FPR/vector unit to the stack, load the value into a GPR, sign
+;; extend it, store it back on the stack from the GPR, load it back into the
+;; FP/vector unit to do the rounding. If we have direct move (ISA 2.07),
+;; disable using store and load to sign/zero extend the value.
 (define_insn_and_split "*round32<mode>2_fprs"
   [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d")
        (float:SFDF
@@ -5399,7 +5401,7 @@ (define_insn_and_split "*round32<mode>2_
    (clobber (match_scratch:DI 3 "=d"))]
   "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
    && <SI_CONVERT_FP> && TARGET_LFIWAX && TARGET_STFIWX && TARGET_FCFID
-   && can_create_pseudo_p ()"
+   && !TARGET_DIRECT_MOVE && can_create_pseudo_p ()"
   "#"
   ""
   [(pc)]
@@ -5431,7 +5433,7 @@ (define_insn_and_split "*roundu32<mode>2
    (clobber (match_scratch:DI 2 "=d"))
    (clobber (match_scratch:DI 3 "=d"))]
   "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
-   && TARGET_LFIWZX && TARGET_STFIWX && TARGET_FCFIDU
+   && TARGET_LFIWZX && TARGET_STFIWX && TARGET_FCFIDU && !TARGET_DIRECT_MOVE
    && can_create_pseudo_p ()"
   "#"
   ""
Index: gcc/testsuite/gcc.target/powerpc/ppc-round2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-round2.c       (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-round2.c       (working copy)
@@ -0,0 +1,42 @@
+/* { 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=power8" } } */
+/* { dg-options "-O2 -mcpu=power8" } */
+/* { dg-final { scan-assembler-times "fcfid "      2 } } */
+/* { dg-final { scan-assembler-times "fcfids "     2 } } */
+/* { dg-final { scan-assembler-times "fctiwuz "    2 } } */
+/* { dg-final { scan-assembler-times "fctiwz "     2 } } */
+/* { dg-final { scan-assembler-times "mfvsrd "     4 } } */
+/* { dg-final { scan-assembler-times "mtvsrwa "    2 } } */
+/* { dg-final { scan-assembler-times "mtvsrwz "    2 } } */
+/* { dg-final { scan-assembler-not   "lwz"           } } */
+/* { dg-final { scan-assembler-not   "lfiwax "       } } */
+/* { dg-final { scan-assembler-not   "lfiwzx "       } } */
+/* { dg-final { scan-assembler-not   "stw"           } } */
+/* { dg-final { scan-assembler-not   "stfiwx "       } } */
+
+/* Make sure we don't have loads/stores to the GPR unit.  */
+double
+round_double_int (double a)
+{
+  return (double)(int)a;
+}
+
+float
+round_float_int (float a)
+{
+  return (float)(int)a;
+}
+
+double
+round_double_uint (double a)
+{
+  return (double)(unsigned int)a;
+}
+
+float
+round_float_uint (float a)
+{
+  return (float)(unsigned int)a;
+}

Reply via email to