https://gcc.gnu.org/g:ca1031c362e7599f6cb03f70279656bf6008f5dc
commit ca1031c362e7599f6cb03f70279656bf6008f5dc Author: Michael Meissner <[email protected]> Date: Tue Jun 9 11:07:14 2026 -0400 Dmf patches 110..113 2026-06-04 Michael Meissner <[email protected]> gcc/ * config/rs6000/rs6000-string.cc (expand_block_move): Do not generate lxvl and stxvl on 32-bit. * config/rs6000/vsx.md (lxvl): If -mcpu=future, generate the lxvl with the shift count automaticaly used in the insn. (lxvrl): New insn for -mcpu=future. (lxvrll): Likewise. (stxvl): If -mcpu=future, generate the stxvl with the shift count automaticaly used in the insn. (stxvrl): New insn for -mcpu=future. (stxvrll): Likewise. gcc/testsuite/ * gcc.target/powerpc/lxvrl.c: New test. 2026-06-04 Michael Meissner <[email protected]> gcc/ * config/rs6000/altivec.md (xvrlw): New insn. * config/rs6000/rs6000.h (TARGET_XVRLW): New macro. gcc/testsuite/ * gcc.target/powerpc/vector-rotate-left.c: New test. 2026-06-04 Michael Meissner <[email protected]> gcc/ * config/rs6000/rs6000.md (gtu_geu): New code iterator. (subfus<mode>3_<code>): New insns. gcc/testsuite/ * gcc.target/powerpc/saturate-subtract-1.c: New test. * gcc.target/powerpc/saturate-subtract-2.c: Likewise. * lib/target-supports.exp (check_effective_target_powerpc_future_ok): New target test. 2026-06-04 Michael Meissner <[email protected]> gcc/ * config/rs6000/rs6000-cpus.def (FUTURE_MASKS_SERVER): Enable using load vector pair and store vector pair instructions for memory copy operations. (POWERPC_MASKS): Make the option for enabling using load vector pair and store vector pair operations set and reset when the PowerPC processor is changed. * config/rs6000/rs6000.cc (rs6000_machine_from_flags): Disable -mblock-ops-vector-pair from influencing .machine selection. gcc/testsuite/ * gcc.target/powerpc/future-3.c: New test. Diff: --- gcc/config/rs6000/altivec.md | 14 +++ gcc/config/rs6000/rs6000-cpus.def | 15 ++- gcc/config/rs6000/rs6000-string.cc | 1 + gcc/config/rs6000/rs6000.cc | 2 +- gcc/config/rs6000/rs6000.h | 3 + gcc/config/rs6000/rs6000.md | 14 +++ gcc/config/rs6000/vsx.md | 122 +++++++++++++++++---- gcc/testsuite/gcc.target/powerpc/future-3.c | 22 ++++ gcc/testsuite/gcc.target/powerpc/lxvrl.c | 32 ++++++ .../gcc.target/powerpc/saturate-subtract-1.c | 39 +++++++ .../gcc.target/powerpc/saturate-subtract-2.c | 40 +++++++ .../gcc.target/powerpc/vector-rotate-left.c | 34 ++++++ gcc/testsuite/lib/target-supports.exp | 13 +++ 13 files changed, 325 insertions(+), 26 deletions(-) diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md index 129f56245cd0..51023c6bcfa0 100644 --- a/gcc/config/rs6000/altivec.md +++ b/gcc/config/rs6000/altivec.md @@ -1982,6 +1982,20 @@ } [(set_attr "type" "vecperm")]) +;; -mcpu=future adds a vector rotate left word variant. There is no vector +;; byte/half-word/double-word/quad-word rotate left. This insn occurs before +;; altivec_vrl<VI_char> and will match for -mcpu=future, while other cpus will +;; match the generic insn. +(define_insn "*xvrlw" + [(set (match_operand:V4SI 0 "register_operand" "=v,wa") + (rotate:V4SI (match_operand:V4SI 1 "register_operand" "v,wa") + (match_operand:V4SI 2 "register_operand" "v,wa")))] + "TARGET_XVRLW" + "@ + vrlw %0,%1,%2 + xvrlw %x0,%x1,%x2" + [(set_attr "type" "vecsimple")]) + (define_insn "altivec_vrl<VI_char>" [(set (match_operand:VI2 0 "register_operand" "=v") (rotate:VI2 (match_operand:VI2 1 "register_operand" "v") diff --git a/gcc/config/rs6000/rs6000-cpus.def b/gcc/config/rs6000/rs6000-cpus.def index 38e6bc880b25..d668953e6a39 100644 --- a/gcc/config/rs6000/rs6000-cpus.def +++ b/gcc/config/rs6000/rs6000-cpus.def @@ -83,10 +83,16 @@ #define POWER11_MASKS_SERVER (ISA_3_1_MASKS_SERVER \ | OPTION_MASK_POWER11) -/* -mcpu=future flags. */ -#define FUTURE_MASKS_SERVER (POWER11_MASKS_SERVER \ - | OPTION_MASK_DENSE_MATH \ - | OPTION_MASK_FUTURE) +/* -mcpu=future flags. + + During the development of the power10 support for GCC, using load/store + vector pair instructions for string operations was turned off by default, + because there was a use case that had really bad performance. Assume this + will be fixed in potential future machines. */ +#define FUTURE_MASKS_SERVER (POWER11_MASKS_SERVER \ + | OPTION_MASK_BLOCK_OPS_VECTOR_PAIR \ + | OPTION_MASK_DENSE_MATH \ + | OPTION_MASK_FUTURE) /* Flags that need to be turned off if -mno-vsx. */ #define OTHER_VSX_VECTOR_MASKS (OPTION_MASK_EFFICIENT_UNALIGNED_VSX \ @@ -116,6 +122,7 @@ /* Mask of all options to set the default isa flags based on -mcpu=<xxx>. */ #define POWERPC_MASKS (OPTION_MASK_ALTIVEC \ + | OPTION_MASK_BLOCK_OPS_VECTOR_PAIR \ | OPTION_MASK_CMPB \ | OPTION_MASK_CRYPTO \ | OPTION_MASK_DENSE_MATH \ diff --git a/gcc/config/rs6000/rs6000-string.cc b/gcc/config/rs6000/rs6000-string.cc index 062ff1e2465e..0c14ba4cc3ea 100644 --- a/gcc/config/rs6000/rs6000-string.cc +++ b/gcc/config/rs6000/rs6000-string.cc @@ -2786,6 +2786,7 @@ expand_block_move (rtx operands[], bool might_overlap) if (TARGET_MMA && TARGET_BLOCK_OPS_UNALIGNED_VSX && TARGET_BLOCK_OPS_VECTOR_PAIR + && TARGET_POWERPC64 && bytes >= 32 && (align >= 256 || !STRICT_ALIGNMENT)) { diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 7a57cb4133e9..9f53eb078b82 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -6016,7 +6016,7 @@ rs6000_machine_from_flags (void) /* Disable the flags that should never influence the .machine selection. */ flags &= ~(OPTION_MASK_PPC_GFXOPT | OPTION_MASK_PPC_GPOPT | OPTION_MASK_ISEL - | OPTION_MASK_ALTIVEC); + | OPTION_MASK_ALTIVEC | OPTION_MASK_BLOCK_OPS_VECTOR_PAIR); if ((flags & (FUTURE_MASKS_SERVER & ~POWER11_MASKS_SERVER)) != 0) return "future"; diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index eef25768b5af..3064db2a7e4e 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -571,6 +571,9 @@ extern int rs6000_vector_align[]; below. */ #define RS6000_FN_TARGET_INFO_HTM 1 +/* Whether we have XVRLW support. */ +#define TARGET_XVRLW TARGET_FUTURE + /* Whether the various reciprocal divide/square root estimate instructions exist, and whether we should automatically generate code for the instruction by default. */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 1ea7bc57ef78..cc49928f59a4 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -2397,6 +2397,20 @@ "" ) +;; Saturating subtract +(define_code_iterator gtu_geu [gtu geu]) + +(define_insn "*subfus<mode>3_<code>" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (if_then_else:GPR (gtu_geu (match_operand:GPR 1 "gpc_reg_operand" "r") + (match_operand:GPR 2 "gpc_reg_operand" "r")) + (minus:GPR (match_dup 1) + (match_dup 2)) + (const_int 0)))] + "TARGET_FUTURE" + "sub<wd>us %0,%1,%2" + [(set_attr "type" "add")]) + (define_insn "@neg<mode>2" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))] diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md index 1305eff8cddb..7a5da0c53319 100644 --- a/gcc/config/rs6000/vsx.md +++ b/gcc/config/rs6000/vsx.md @@ -5712,20 +5712,32 @@ DONE; }) -;; Load VSX Vector with Length +;; Load VSX Vector with Length. If we have lxvrl, we don't have to do an +;; explicit shift left into a pseudo. (define_expand "lxvl" - [(set (match_dup 3) - (ashift:DI (match_operand:DI 2 "register_operand") - (const_int 56))) - (set (match_operand:V16QI 0 "vsx_register_operand") - (unspec:V16QI - [(match_operand:DI 1 "gpc_reg_operand") - (mem:V16QI (match_dup 1)) - (match_dup 3)] - UNSPEC_LXVL))] + [(use (match_operand:V16QI 0 "vsx_register_operand")) + (use (match_operand:DI 1 "gpc_reg_operand")) + (use (match_operand:DI 2 "gpc_reg_operand"))] "TARGET_P9_VECTOR && TARGET_64BIT" { - operands[3] = gen_reg_rtx (DImode); + rtx shift_len = gen_rtx_ASHIFT (DImode, operands[2], GEN_INT (56)); + rtx len; + + if (TARGET_FUTURE) + len = shift_len; + else + { + len = gen_reg_rtx (DImode); + emit_insn (gen_rtx_SET (len, shift_len)); + } + + rtx dest = operands[0]; + rtx addr = operands[1]; + rtx mem = gen_rtx_MEM (V16QImode, addr); + rtvec rv = gen_rtvec (3, addr, mem, len); + rtx lxvl = gen_rtx_UNSPEC (V16QImode, rv, UNSPEC_LXVL); + emit_insn (gen_rtx_SET (dest, lxvl)); + DONE; }) (define_insn "*lxvl" @@ -5749,6 +5761,34 @@ "lxvll %x0,%1,%2" [(set_attr "type" "vecload")]) +;; For lxvrl and lxvrll, use the combiner to eliminate the shift. The +;; define_expand for lxvl will already incorporate the shift in generating the +;; insn. The lxvll buitl-in function required the user to have already done +;; the shift. Defining lxvrll this way, will optimize cases where the user has +;; done the shift immediately before the built-in. +(define_insn "*lxvrl" + [(set (match_operand:V16QI 0 "vsx_register_operand" "=wa") + (unspec:V16QI + [(match_operand:DI 1 "gpc_reg_operand" "b") + (mem:V16QI (match_dup 1)) + (ashift:DI (match_operand:DI 2 "register_operand" "r") + (const_int 56))] + UNSPEC_LXVL))] + "TARGET_FUTURE && TARGET_64BIT" + "lxvrl %x0,%1,%2" + [(set_attr "type" "vecload")]) + +(define_insn "*lxvrll" + [(set (match_operand:V16QI 0 "vsx_register_operand" "=wa") + (unspec:V16QI [(match_operand:DI 1 "gpc_reg_operand" "b") + (mem:V16QI (match_dup 1)) + (ashift:DI (match_operand:DI 2 "register_operand" "r") + (const_int 56))] + UNSPEC_LXVLL))] + "TARGET_FUTURE" + "lxvrll %x0,%1,%2" + [(set_attr "type" "vecload")]) + ;; Expand for builtin xl_len_r (define_expand "xl_len_r" [(match_operand:V16QI 0 "vsx_register_operand") @@ -5780,18 +5820,29 @@ ;; Store VSX Vector with Length (define_expand "stxvl" - [(set (match_dup 3) - (ashift:DI (match_operand:DI 2 "register_operand") - (const_int 56))) - (set (mem:V16QI (match_operand:DI 1 "gpc_reg_operand")) - (unspec:V16QI - [(match_operand:V16QI 0 "vsx_register_operand") - (mem:V16QI (match_dup 1)) - (match_dup 3)] - UNSPEC_STXVL))] + [(use (match_operand:V16QI 0 "vsx_register_operand")) + (use (match_operand:DI 1 "gpc_reg_operand")) + (use (match_operand:DI 2 "gpc_reg_operand"))] "TARGET_P9_VECTOR && TARGET_64BIT" { - operands[3] = gen_reg_rtx (DImode); + rtx shift_len = gen_rtx_ASHIFT (DImode, operands[2], GEN_INT (56)); + rtx len; + + if (TARGET_FUTURE) + len = shift_len; + else + { + len = gen_reg_rtx (DImode); + emit_insn (gen_rtx_SET (len, shift_len)); + } + + rtx src = operands[0]; + rtx addr = operands[1]; + rtx mem = gen_rtx_MEM (V16QImode, addr); + rtvec rv = gen_rtvec (3, src, mem, len); + rtx stxvl = gen_rtx_UNSPEC (V16QImode, rv, UNSPEC_STXVL); + emit_insn (gen_rtx_SET (mem, stxvl)); + DONE; }) ;; Define optab for vector access with length vectorization exploitation. @@ -5836,6 +5887,35 @@ "stxvl %x0,%1,%2" [(set_attr "type" "vecstore")]) +;; For stxvrl and stxvrll, use the combiner to eliminate the shift. The +;; define_expand for stxvl will already incorporate the shift in generating the +;; insn. The stxvll buitl-in function required the user to have already done +;; the shift. Defining stxvrll this way, will optimize cases where the user +;; has done the shift immediately before the built-in. + +(define_insn "*stxvrl" + [(set (mem:V16QI (match_operand:DI 1 "gpc_reg_operand" "b")) + (unspec:V16QI + [(match_operand:V16QI 0 "vsx_register_operand" "wa") + (mem:V16QI (match_dup 1)) + (ashift:DI (match_operand:DI 2 "register_operand" "r") + (const_int 56))] + UNSPEC_STXVL))] + "TARGET_FUTURE && TARGET_64BIT" + "stxvrl %x0,%1,%2" + [(set_attr "type" "vecstore")]) + +(define_insn "*stxvrll" + [(set (mem:V16QI (match_operand:DI 1 "gpc_reg_operand" "b")) + (unspec:V16QI [(match_operand:V16QI 0 "vsx_register_operand" "wa") + (mem:V16QI (match_dup 1)) + (ashift:DI (match_operand:DI 2 "register_operand" "r") + (const_int 56))] + UNSPEC_STXVLL))] + "TARGET_FUTURE" + "stxvrll %x0,%1,%2" + [(set_attr "type" "vecstore")]) + ;; Expand for builtin xst_len_r (define_expand "xst_len_r" [(match_operand:V16QI 0 "vsx_register_operand" "=wa") diff --git a/gcc/testsuite/gcc.target/powerpc/future-3.c b/gcc/testsuite/gcc.target/powerpc/future-3.c new file mode 100644 index 000000000000..afa22228b96d --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/future-3.c @@ -0,0 +1,22 @@ +/* 32-bit doesn't generate vector pair instructions. */ +/* { dg-do compile { target lp64 } } */ +/* { dg-options "-mdejagnu-cpu=future -O2" } */ + +/* Test to see that memcpy will use load/store vector pair with + -mcpu=future. */ + +#ifndef SIZE +#define SIZE 4 +#endif + +extern vector double to[SIZE], from[SIZE]; + +void +copy (void) +{ + __builtin_memcpy (to, from, sizeof (to)); + return; +} + +/* { dg-final { scan-assembler {\mlxvpx?\M} } } */ +/* { dg-final { scan-assembler {\mstxvpx?\M} } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/lxvrl.c b/gcc/testsuite/gcc.target/powerpc/lxvrl.c new file mode 100644 index 000000000000..71854c50c911 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/lxvrl.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target powerpc_future_ok } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-options "-mdejagnu-cpu=future -O2" } */ + +/* Test whether the lxvrl and stxvrl instructions are generated for + -mcpu=future on memory copy operations. */ + +#ifndef VSIZE +#define VSIZE 2 +#endif + +#ifndef LSIZE +#define LSIZE 5 +#endif + +struct foo { + vector unsigned char vc[VSIZE]; + unsigned char leftover[LSIZE]; +}; + +void memcpy_ptr (struct foo *p, struct foo *q) +{ + __builtin_memcpy ((void *) p, /* lxvrl and stxvrl. */ + (void *) q, + (sizeof (vector unsigned char) * VSIZE) + LSIZE); +} + +/* { dg-final { scan-assembler {\mlxvrl\M} } } */ +/* { dg-final { scan-assembler {\mstxvrl\M} } } */ +/* { dg-final { scan-assembler-not {\mlxvl\M} } } */ +/* { dg-final { scan-assembler-not {\mstxvl\M} } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/saturate-subtract-1.c b/gcc/testsuite/gcc.target/powerpc/saturate-subtract-1.c new file mode 100644 index 000000000000..c32a70a5e898 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/saturate-subtract-1.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-mdejagnu-cpu=future -O2" } */ +/* { dg-require-effective-target powerpc_future_ok } */ + +/* Check that saturating subtract (subfus) is generated. Check that all + combinations of >, >=, <, and <= are optimized. */ + +#ifndef TYPE +#define TYPE unsigned int +#endif + +void +saturated_subtract_gt (TYPE a, TYPE b, TYPE *p) +{ + *p = (a > b) ? a - b : 0; +} + +void +saturated_subtract_ge (TYPE a, TYPE b, TYPE *p) +{ + *p = (a >= b) ? a - b : 0; +} + +void +saturated_subtract_lt (TYPE a, TYPE b, TYPE *p) +{ + *p = (a < b) ? 0 : a - b; +} + +void +saturated_subtract_le (TYPE a, TYPE b, TYPE *p) +{ + *p = (a <= b) ? 0 : a - b; +} + +/* { dg-final { scan-assembler-times {\msubwus\M} 4 } } */ +/* { dg-final { scan-assembler-not {\mcmplw\M} } } */ +/* { dg-final { scan-assembler-not {\misel\M} } } */ +/* { dg-final { scan-assembler-not {\msubf\M} } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/saturate-subtract-2.c b/gcc/testsuite/gcc.target/powerpc/saturate-subtract-2.c new file mode 100644 index 000000000000..482d7384c172 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/saturate-subtract-2.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target powerpc_future_ok } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-options "-mdejagnu-cpu=future -O2" } */ + +/* Check that saturating subtract (subfus) is generated. Check that all + combinations of >, >=, <, and <= are optimized. */ + +#ifndef TYPE +#define TYPE unsigned long long +#endif + +void +saturated_subtract_gt (TYPE a, TYPE b, TYPE *p) +{ + *p = (a > b) ? a - b : 0; +} + +void +saturated_subtract_ge (TYPE a, TYPE b, TYPE *p) +{ + *p = (a >= b) ? a - b : 0; +} + +void +saturated_subtract_lt (TYPE a, TYPE b, TYPE *p) +{ + *p = (a < b) ? 0 : a - b; +} + +void +saturated_subtract_le (TYPE a, TYPE b, TYPE *p) +{ + *p = (a <= b) ? 0 : a - b; +} + +/* { dg-final { scan-assembler-times {\msubdus\M} 4 } } */ +/* { dg-final { scan-assembler-not {\mcmpld\M} } } */ +/* { dg-final { scan-assembler-not {\misel\M} } } */ +/* { dg-final { scan-assembler-not {\msubf\M} } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/vector-rotate-left.c b/gcc/testsuite/gcc.target/powerpc/vector-rotate-left.c new file mode 100644 index 000000000000..f9e87ad4bfcf --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/vector-rotate-left.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target powerpc_future_ok } */ +/* { dg-options "-mdejagnu-cpu=future -O2" } */ + +/* Test whether the xvrl (vector word rotate left using VSX registers insead of + Altivec registers is generated. */ + +#include <altivec.h> + +typedef vector unsigned int v4si_t; + +v4si_t +rotl_v4si_scalar (v4si_t x, unsigned long n) +{ + __asm__ (" # %x0" : "+f" (x)); + return (x << n) | (x >> (32 - n)); /* xvrlw. */ +} + +v4si_t +rotr_v4si_scalar (v4si_t x, unsigned long n) +{ + __asm__ (" # %x0" : "+f" (x)); + return (x >> n) | (x << (32 - n)); /* xvrlw. */ +} + +v4si_t +rotl_v4si_vector (v4si_t x, v4si_t y) +{ + __asm__ (" # %x0" : "+f" (x)); /* xvrlw. */ + return vec_rl (x, y); +} + +/* { dg-final { scan-assembler-times {\mxvrlw\M} 3 } } */ +/* { dg-final { scan-assembler-not {\mvrlw\M} } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index cba178b937f8..9a6c74be6fc5 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -8255,6 +8255,19 @@ proc check_htm_hw_available { } { } }] } + +# Return 1 if this is a PowerPC target supporting -mcpu=future + +proc check_effective_target_powerpc_future_ok { } { + return [check_no_compiler_messages powerpc_future_ok object { + unsigned long a, b, c; + int main (void) { + asm ("subdus %0,%1,%2" : "=r" (a) : "r" (b), "r" (c)); + return 0; + } + } "-mcpu=future"] +} + # Return 1 if this is a PowerPC target supporting -mcpu=cell. proc check_effective_target_powerpc_ppu_ok { } {
