Hi, Swap optimization is missing some opportunities when vector reductions are present. This patch adds logic to recognize vector-reduction patterns and mark them as swappable. Some of these are very easy to recognize, given the presence of a specific unspec. For V2DF reductions, we have to recognize a specific somewhat complex pattern.
I've added test cases to verify swap optimization works correctly on reductions for V2DF and V4SF. Bootstrapped and tested on powerpc64le-unknown-linux-gnu with no regressions. Is this ok for trunk? I would also like to backport this to GCC 5 after a settling period. Thanks, Bill [gcc] 2016-01-06 Bill Schmidt <wschm...@linux.vnet.ibm.com> * config/rs6000/rs6000.c (v2df_reduction_p): New function. (rtx_is_swappable_p): Reductions are swappable. (insn_is_swappable_p): V2DF reductions are swappable. [gcc/testsuite] 2016-01-06 Bill Schmidt <wschm...@linux.vnet.ibm.com> * gcc.target/powerpc/swaps-p8-23.c: New test. * gcc.target/powerpc/swaps-p8-24.c: Likewise. Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 232109) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -36648,6 +36648,44 @@ const_load_sequence_p (swap_web_entry *insn_entry, return true; } +/* Return TRUE iff OP matches a V2DF reduction pattern. See the + definition of vsx_reduc_<VEC_reduc_name>_v2df in vsx.md. */ +static bool +v2df_reduction_p (rtx op) +{ + if (GET_MODE (op) != V2DFmode) + return false; + + enum rtx_code code = GET_CODE (op); + if (code != PLUS && code != SMIN && code != SMAX) + return false; + + rtx concat = XEXP (op, 0); + if (GET_CODE (concat) != VEC_CONCAT) + return false; + + rtx select0 = XEXP (concat, 0); + rtx select1 = XEXP (concat, 1); + if (GET_CODE (select0) != VEC_SELECT || GET_CODE (select1) != VEC_SELECT) + return false; + + rtx reg0 = XEXP (select0, 0); + rtx reg1 = XEXP (select1, 0); + if (!rtx_equal_p (reg0, reg1) || !REG_P (reg0)) + return false; + + rtx parallel0 = XEXP (select0, 1); + rtx parallel1 = XEXP (select1, 1); + if (GET_CODE (parallel0) != PARALLEL || GET_CODE (parallel1) != PARALLEL) + return false; + + if (!rtx_equal_p (XVECEXP (parallel0, 0, 0), const1_rtx) + || !rtx_equal_p (XVECEXP (parallel1, 0, 0), const0_rtx)) + return false; + + return true; +} + /* Return 1 iff OP is an operand that will not be affected by having vector doublewords swapped in memory. */ static unsigned int @@ -36719,6 +36757,8 @@ rtx_is_swappable_p (rtx op, unsigned int *special) *special = SH_XXPERMDI; return 1; } + else if (v2df_reduction_p (op)) + return 1; else return 0; @@ -36783,6 +36823,9 @@ rtx_is_swappable_p (rtx op, unsigned int *special) case UNSPEC_VSPLT_DIRECT: *special = SH_SPLAT; return 1; + case UNSPEC_REDUC_PLUS: + case UNSPEC_REDUC: + return 1; } } @@ -36907,6 +36950,15 @@ insn_is_swappable_p (swap_web_entry *insn_entry, r return 1; } + /* V2DF reductions are always swappable. */ + if (GET_CODE (body) == PARALLEL) + { + rtx expr = XVECEXP (body, 0, 0); + if (GET_CODE (expr) == SET + && v2df_reduction_p (SET_SRC (expr))) + return 1; + } + /* An UNSPEC_VPERM is ok if the mask operand is loaded from the constant pool. */ if (GET_CODE (body) == SET Index: gcc/testsuite/gcc.target/powerpc/swaps-p8-23.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/swaps-p8-23.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/swaps-p8-23.c (working copy) @@ -0,0 +1,26 @@ +/* { dg-do compile { target { powerpc64le-*-* } } } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */ +/* { dg-options "-mcpu=power8 -O3 -ffast-math" } */ +/* { dg-final { scan-assembler "lxvd2x" } } */ +/* { dg-final { scan-assembler-not "xxpermdi" } } */ + +/* Verify that swap optimization works correctly in the presence of + a V2DFmode reduction. */ + +extern double optvalue; +extern void obfuscate (double, unsigned int); + +void +foo (double *x, double *y, unsigned int n, unsigned int m) +{ + unsigned int i, j; + double sacc; + for (j = 0; j < m; ++j) + { + sacc = 0.0; + for (i = 0; i < n; ++i) + sacc += x[i] * y[i]; + obfuscate (sacc, n); + } + optvalue = n * 2.0 * m; +} Index: gcc/testsuite/gcc.target/powerpc/swaps-p8-24.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/swaps-p8-24.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/swaps-p8-24.c (working copy) @@ -0,0 +1,26 @@ +/* { dg-do compile { target { powerpc64le-*-* } } } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */ +/* { dg-options "-mcpu=power8 -O3 -ffast-math" } */ +/* { dg-final { scan-assembler "lxvd2x" } } */ +/* { dg-final { scan-assembler-not "xxpermdi" } } */ + +/* Verify that swap optimization works correctly in the presence of + a V4SFmode reduction. */ + +extern double optvalue; +extern void obfuscate (float, unsigned int); + +void +foo (float *x, float *y, unsigned int n, unsigned int m) +{ + unsigned int i, j; + float sacc; + for (j = 0; j < m; ++j) + { + sacc = 0.0f; + for (i = 0; i < n; ++i) + sacc += x[i] * y[i]; + obfuscate (sacc, n); + } + optvalue = n * 2.0f * m; +}