https://gcc.gnu.org/g:c625a016f1dd3ca80d36f6ddb6559db481042069

commit c625a016f1dd3ca80d36f6ddb6559db481042069
Author: Michael Meissner <[email protected]>
Date:   Tue Jun 9 11:10:20 2026 -0400

    Bugs patches 300 .. 304
    
    2026-06-04  Michael Meissner  <[email protected]>
    
    gcc/
    
            PR target/120681
            * config/rs6000/linux64.h (PCREL_SUPPORTED_BY_OS): Allow large
            code model as well as medium code model.
            * config/rs6000/rs6000.cc (rs6000_option_override_internal):
            Likewise.
            (rs6000_elf_declare_function_name): Don't create the
            local/non-local labels for large code model if we are using
            PC-relative addressing.
    
    gcc/testsuite/
    
            PR target/120681
            * gcc.target/powerpc/pr120681.c: New test.
    
    2026-06-04  Michael Meissner  <[email protected]>
    
    gcc/
    
            PR target/108958
            * config/rs6000/rs6000.md (UNSPEC_ZERO_EXTEND): New unspec.
            (zero_extendsiti2 peephole2): Add a peephole2 to simplify zero
            extend between DImode value in a GPR to a TImode target in a
            vector register.
            (zero_extendsiti2_vsx): New insn.
    
    gcc/testsuite/
    
            PR target/108958
            * gcc.target/powerpc/pr108958.c: New test.
    
    2026-06-04  Michael Meissner  <[email protected]>
    
    gcc/
    
            PR target/120528
            * config/rs6000/rs6000.md (zero_extend??ti2 peephole2): Add a
            peephole2 to simplify zero extending a QI/HI/SI/DImode value in
            memory to a TImode target in a vector register to use the
            LXVR{B,H,W,D}X instructins.
    
    gcc/testsuite/
    
            PR target/120528
            * gcc.target/powerpc/pr120528.c: New test.
    
    2026-06-04  Michael Meissner  <[email protected]>
    
    gcc/
    
            PR target/99293
            * config/rs6000/vsx.md (vsx_splat_extract_<mode>): New insn.
    
    gcc/testsuite/
    
            PR target/99293
            * gcc.target/powerpc/pr99293.c: New test.
    
    2026-06-04  Michael Meissner  <[email protected]>
    
    gcc/
    
            PR target/117487
            * config/rs6000/vsx.md (SFmode logical peephoole): Update comments 
in
            the original code that supports power8.
            (SFBOOL2_*): New constants.
            (power9/power10 define_peephol2): Add a new define_peephole2 to 
optimize
            float and logical operations on power9/power10/power11 similar to 
the
            optimiztion that is done on power8.
    
    gcc/testsuite/
    
            PR target/117487
            * gcc.target/powerpc/pr117487.c: New test.

Diff:
---
 gcc/config/rs6000/linux64.h                 |   5 +-
 gcc/config/rs6000/rs6000.cc                 |  13 ++-
 gcc/config/rs6000/rs6000.md                 |  95 +++++++++++++++++
 gcc/config/rs6000/vsx.md                    | 160 +++++++++++++++++++++++++++-
 gcc/testsuite/gcc.target/powerpc/pr108958.c |  47 ++++++++
 gcc/testsuite/gcc.target/powerpc/pr117487.c |  67 ++++++++++++
 gcc/testsuite/gcc.target/powerpc/pr120528.c |  91 ++++++++++++++++
 gcc/testsuite/gcc.target/powerpc/pr120681.c |  34 ++++++
 gcc/testsuite/gcc.target/powerpc/pr99293.c  |  22 ++++
 9 files changed, 522 insertions(+), 12 deletions(-)

diff --git a/gcc/config/rs6000/linux64.h b/gcc/config/rs6000/linux64.h
index 1af710303687..c892930a8a93 100644
--- a/gcc/config/rs6000/linux64.h
+++ b/gcc/config/rs6000/linux64.h
@@ -564,7 +564,8 @@ extern int dot_symbols;
 
 /* Enable using prefixed PC-relative addressing on POWER10 if the ABI
    supports it.  The ELF v2 ABI only supports PC-relative relocations for
-   the medium code model.  */
+   the medium/large code models.  */
 #define PCREL_SUPPORTED_BY_OS  (TARGET_POWER10 && TARGET_PREFIXED      \
                                 && ELFv2_ABI_CHECK                     \
-                                && TARGET_CMODEL == CMODEL_MEDIUM)
+                                && (TARGET_CMODEL == CMODEL_MEDIUM     \
+                                    || TARGET_CMODEL == CMODEL_LARGE))
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 204916ad50cd..efab305a51b5 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -4454,12 +4454,15 @@ rs6000_option_override_internal (bool global_init_p)
       && (rs6000_isa_flags_explicit & OPTION_MASK_PCREL) == 0)
     rs6000_isa_flags |= OPTION_MASK_PCREL;
 
-  /* -mpcrel requires -mcmodel=medium, but we can't check TARGET_CMODEL until
-      after the subtarget override options are done.  */
-  else if (TARGET_PCREL && TARGET_CMODEL != CMODEL_MEDIUM)
+  /* -mpcrel requires medium or large code models, but we can't check
+      TARGET_CMODEL until after the subtarget override options are done.  */
+  else if (TARGET_PCREL
+          && TARGET_CMODEL != CMODEL_MEDIUM
+          && TARGET_CMODEL != CMODEL_LARGE)
     {
       if ((rs6000_isa_flags_explicit & OPTION_MASK_PCREL) != 0)
-       error ("%qs requires %qs", "-mpcrel", "-mcmodel=medium");
+       error ("%qs requires %qs or %qs", "-mpcrel", "-mcmodel=medium",
+              "-mcmodel=large");
 
       rs6000_isa_flags &= ~OPTION_MASK_PCREL;
     }
@@ -21530,7 +21533,7 @@ rs6000_elf_declare_function_name (FILE *file, const 
char *name, tree decl)
   ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
   ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
 
-  if (TARGET_CMODEL == CMODEL_LARGE
+  if (TARGET_CMODEL == CMODEL_LARGE && !TARGET_PCREL
       && rs6000_global_entry_point_prologue_needed_p ())
     {
       char buf[256];
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 2c44e24a06db..9fa13fe2ad8c 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -175,6 +175,7 @@
    UNSPEC_XXSPLTIW_CONST
    UNSPEC_FMAX
    UNSPEC_FMIN
+   UNSPEC_ZERO_EXTEND
   ])
 
 ;;
@@ -976,6 +977,100 @@
    (set_attr "dot" "yes")
    (set_attr "length" "4,8")])
 
+;; Optimize zero_extendsiti2 from a GPR to a GPR and then moving the GPR to a
+;; VSX register
+(define_peephole2
+  [(set (match_operand:DI 0 "int_reg_operand")
+       (match_operand:DI 1 "int_reg_operand"))
+   (set (match_operand:DI 2 "int_reg_operand")
+       (const_int 0))
+   (set (match_operand:TI 3 "vsx_register_operand")
+       (match_operand:TI 4 "int_reg_operand"))]
+  "TARGET_DIRECT_MOVE_64BIT
+   && (reg_or_subregno (operands[0])
+       == reg_or_subregno (operands[4]) + !!WORDS_BIG_ENDIAN)
+   && (reg_or_subregno (operands[2])
+       == reg_or_subregno (operands[4]) + !WORDS_BIG_ENDIAN)
+   && peep2_reg_dead_p (3, operands[4])"
+  [(set (match_dup 3)
+       (unspec:TI [(match_dup 1)] UNSPEC_ZERO_EXTEND))])
+
+(define_insn "*zero_extendsiti2_vsx"
+  [(set (match_operand:TI 0 "vsx_register_operand" "=wa")
+       (unspec:TI [(match_operand:DI 1 "int_reg_operand" "r")]
+                  UNSPEC_ZERO_EXTEND))]
+  "TARGET_DIRECT_MOVE_64BIT"
+  "mtvsrdd %x0,0,%1"
+  [(set_attr "type" "mtvsr")])
+
+;; On power10, optimize zero extending a QI/HI/SI/DImode value from memory that
+;; is going to a vector register target by generating a LXVR{B,H,W,D}X
+;; instruction without creating the TImode value in a GPR and using MTVSRDD to
+;; move it to the vector register.
+(define_peephole2
+  [(set (match_operand:DI 0 "int_reg_operand")
+       (match_operand:DI 1 "memory_operand"))
+   (set (match_operand:DI 2 "base_reg_operand")
+       (const_int 0))
+   (set (match_operand:TI 3 "vsx_register_operand")
+       (match_operand:TI 4 "int_reg_operand"))]
+  "TARGET_POWER10 && TARGET_POWERPC64
+   && (reg_or_subregno (operands[0])
+       == reg_or_subregno (operands[4]) + !!WORDS_BIG_ENDIAN)
+   && (reg_or_subregno (operands[2])
+       == reg_or_subregno (operands[4]) + !WORDS_BIG_ENDIAN)
+   && peep2_reg_dead_p (3, operands[4])
+   && (REG_P (XEXP (operands[1], 0))
+       || SUBREG_P (XEXP (operands[1], 0))
+       || GET_CODE (XEXP (operands[1], 0)) == PLUS)"
+  [(set (match_dup 3)
+       (zero_extend:TI (match_dup 5)))]
+{
+  rtx mem = operands[1];
+  rtx addr = XEXP (mem, 0);
+
+  if (indexed_or_indirect_address (addr, DImode))
+    operands[5] = mem;
+  else
+    {
+      rtx op2 = operands[2];
+      emit_insn (gen_rtx_SET (op2, addr));
+      operands[5] = change_address (mem, DImode, op2);
+    }
+})
+
+(define_peephole2
+  [(set (match_operand:DI 0 "int_reg_operand")
+       (zero_extend:DI
+        (match_operand:QHSI 1 "memory_operand")))
+   (set (match_operand:DI 2 "base_reg_operand")
+       (const_int 0))
+   (set (match_operand:TI 3 "vsx_register_operand")
+       (match_operand:TI 4 "int_reg_operand"))]
+  "TARGET_POWER10 && TARGET_POWERPC64
+   && (reg_or_subregno (operands[0])
+       == reg_or_subregno (operands[4]) + !!WORDS_BIG_ENDIAN)
+   && (reg_or_subregno (operands[2])
+       == reg_or_subregno (operands[4]) + !WORDS_BIG_ENDIAN)
+   && peep2_reg_dead_p (3, operands[4])
+   && (REG_P (XEXP (operands[1], 0))
+       || SUBREG_P (XEXP (operands[1], 0))
+       || GET_CODE (XEXP (operands[1], 0)) == PLUS)"
+  [(set (match_dup 3)
+       (zero_extend:TI (match_dup 5)))]
+{
+  rtx mem = operands[1];
+  rtx addr = XEXP (mem, 0);
+
+  if (indexed_or_indirect_address (addr, DImode))
+    operands[5] = mem;
+  else
+    {
+      rtx op2 = operands[2];
+      emit_insn (gen_rtx_SET (op2, addr));
+      operands[5] = change_address (mem, DImode, op2);
+    }
+})
 
 (define_insn "zero_extendsi<mode>2"
   [(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r,r,d,wa,wa,r,wa")
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index 7a5da0c53319..db52228789f2 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -4798,6 +4798,24 @@
   "lxvdsx %x0,%y1"
   [(set_attr "type" "vecload")])
 
+;; Optimize SPLAT of an extract from a V2DF/V2DI vector with a constant element
+(define_insn "*vsx_splat_extract_<mode>"
+  [(set (match_operand:VSX_D 0 "vsx_register_operand" "=wa")
+       (vec_duplicate:VSX_D
+        (vec_select:<VEC_base>
+         (match_operand:VSX_D 1 "vsx_register_operand" "wa")
+         (parallel [(match_operand 2 "const_0_to_1_operand" "n")]))))]
+  "VECTOR_MEM_VSX_P (<MODE>mode)"
+{
+  int which_word = INTVAL (operands[2]);
+  if (!BYTES_BIG_ENDIAN)
+    which_word = 1 - which_word;
+
+  operands[3] = GEN_INT (which_word ? 3 : 0);
+  return "xxpermdi %x0,%x1,%x1,%3";
+}
+  [(set_attr "type" "vecperm")])
+
 ;; V4SI splat support
 (define_insn "vsx_splat_v4si"
   [(set (match_operand:V4SI 0 "vsx_register_operand" "=wa,wa")
@@ -6345,7 +6363,7 @@
    (SFBOOL_MFVSR_A              3)             ;; move to gpr src
    (SFBOOL_BOOL_D               4)             ;; and/ior/xor dest
    (SFBOOL_BOOL_A1              5)             ;; and/ior/xor arg1
-   (SFBOOL_BOOL_A2              6)             ;; and/ior/xor arg1
+   (SFBOOL_BOOL_A2              6)             ;; and/ior/xor arg2
    (SFBOOL_SHL_D                7)             ;; shift left dest
    (SFBOOL_SHL_A                8)             ;; shift left arg
    (SFBOOL_MTVSR_D              9)             ;; move to vecter dest
@@ -6385,18 +6403,18 @@
 ;; GPR, and instead move the integer mask value to the vector register after a
 ;; shift and do the VSX logical operation.
 
-;; The insns for dealing with SFmode in GPR registers looks like:
+;; The insns for dealing with SFmode in GPR registers looks like on power8:
 ;; (set (reg:V4SF reg2) (unspec:V4SF [(reg:SF reg1)] UNSPEC_VSX_CVDPSPN))
 ;;
-;; (set (reg:DI reg3) (unspec:DI [(reg:V4SF reg2)] UNSPEC_P8V_RELOAD_FROM_VSX))
+;; (set (reg:DI reg3) (zero_extend:DI (reg:SI reg2)))
 ;;
-;; (set (reg:DI reg4) (and:DI (reg:DI reg3) (reg:DI reg3)))
+;; (set (reg:DI reg4) (and:SI (reg:SI reg3) (reg:SI mask)))
 ;;
 ;; (set (reg:DI reg5) (ashift:DI (reg:DI reg4) (const_int 32)))
 ;;
 ;; (set (reg:SF reg6) (unspec:SF [(reg:DI reg5)] UNSPEC_P8V_MTVSRD))
 ;;
-;; (set (reg:SF reg6) (unspec:SF [(reg:SF reg6)] UNSPEC_VSX_CVSPDPN))
+;; (set (reg:SF reg7) (unspec:SF [(reg:SF reg6)] UNSPEC_VSX_CVSPDPN))
 
 (define_peephole2
   [(match_scratch:DI SFBOOL_TMP_GPR "r")
@@ -6477,6 +6495,138 @@
   operands[SFBOOL_MTVSR_D_V4SF] = gen_rtx_REG (V4SFmode, regno_mtvsr_d);
 })
 
+;; Constants for SFbool optimization on power9/power10
+(define_constants
+  [(SFBOOL2_TMP_VSX_V4SI        0)             ;; vector temporary (V4SI)
+   (SFBOOL2_TMP_GPR_SI          1)             ;; GPR temporary (SI)
+   (SFBOOL2_MFVSR_D             2)             ;; move to gpr dest (DI)
+   (SFBOOL2_MFVSR_A             3)             ;; move to gpr src (SI)
+   (SFBOOL2_BOOL_D              4)             ;; and/ior/xor dest (SI)
+   (SFBOOL2_BOOL_A1             5)             ;; and/ior/xor arg1 (SI)
+   (SFBOOL2_BOOL_A2             6)             ;; and/ior/xor arg2 (SI)
+   (SFBOOL2_SPLAT_D             7)             ;; splat dest (V4SI)
+   (SFBOOL2_MTVSR_D             8)             ;; move/splat to VSX dest.
+   (SFBOOL2_MTVSR_A             9)             ;; move/splat to VSX arg.
+   (SFBOOL2_MFVSR_A_V4SI       10)             ;; MFVSR_A as V4SI
+   (SFBOOL2_MTVSR_D_V4SI       11)             ;; MTVSR_D as V4SI
+   (SFBOOL2_XXSPLTW            12)])           ;; 1 or 3 for XXSPLTW
+
+;; On power9/power10, the code is different because we have a splat 32-bit
+;; operation that does a direct move to the FPR/vector registers (MTVSRWS).
+;;
+;; The insns for dealing with SFmode in GPR registers looks like on
+;; power9/power10:
+;;
+;; (set (reg:V4SF reg2) (unspec:V4SF [(reg:SF reg1)] UNSPEC_VSX_CVDPSPN))
+;;
+;; (set (reg:DI reg3) (zero_extend:DI (reg:SI reg2)))
+;;
+;; (set (reg:SI reg4) (and:SI (reg:SI reg3) (reg:SI mask)))
+;;
+;; (set (reg:V4SI reg5) (vec_duplicate:V4SI (reg:SI reg4)))
+;;
+;; (set (reg:SF reg6) (unspec:SF [(reg:SF reg5)] UNSPEC_VSX_CVSPDPN))
+
+;; The VSX temporary needs to be an Altivec register in case we are trying to
+;; do and/ior/xor of -16..15 and we want to use VSPLTISW to load the constant.
+;;
+;; The GPR temporary is only used if we are trying to do a logical operation
+;; with a constant outside of the -16..15 range on a power9.  Otherwise, we can
+;; load the constant directly into the VSX temporary register.
+
+(define_peephole2
+  [(match_scratch:V4SI SFBOOL2_TMP_VSX_V4SI "v")
+   (match_scratch:SI SFBOOL2_TMP_GPR_SI "r")
+
+   ;; Zero_extend and direct move
+   (set (match_operand:DI SFBOOL2_MFVSR_D "int_reg_operand")
+       (zero_extend:DI
+        (match_operand:SI SFBOOL2_MFVSR_A "vsx_register_operand")))
+
+   ;; AND/IOR/XOR operation on int
+   (set (match_operand:SI SFBOOL2_BOOL_D "int_reg_operand")
+       (and_ior_xor:SI
+        (match_operand:SI SFBOOL2_BOOL_A1 "int_reg_operand")
+        (match_operand:SI SFBOOL2_BOOL_A2 "reg_or_cint_operand")))
+
+   ;; Splat sfbool result to vector register
+   (set (match_operand:V4SI SFBOOL2_SPLAT_D "vsx_register_operand")
+       (vec_duplicate:V4SI
+        (match_dup SFBOOL2_BOOL_D)))]
+
+  "TARGET_POWERPC64 && TARGET_P9_VECTOR
+   && REG_P (operands[SFBOOL2_MFVSR_D])
+   && REG_P (operands[SFBOOL2_BOOL_A1])
+   && (REGNO (operands[SFBOOL2_MFVSR_D]) == REGNO (operands[SFBOOL2_BOOL_A1])
+       || (REG_P (operands[SFBOOL2_BOOL_A2])
+           && (REGNO (operands[SFBOOL2_MFVSR_D])
+               == REGNO (operands[SFBOOL2_BOOL_A2]))))
+   && peep2_reg_dead_p (3, operands[SFBOOL2_MFVSR_D])
+   && peep2_reg_dead_p (4, operands[SFBOOL2_BOOL_D])"
+
+  ;; Either (set (reg:SI xxx) (reg:SI yyy))    or
+  ;;        (set (reg:V4SI xxx) (const_vector (parallel [c, c, c, c])))
+  [(set (match_dup SFBOOL2_MTVSR_D)
+       (match_dup SFBOOL2_MTVSR_A))
+
+   ;; And/ior/xor on vector registers
+   (set (match_dup SFBOOL2_TMP_VSX_V4SI)
+       (and_ior_xor:V4SI
+        (match_dup SFBOOL2_MFVSR_A_V4SI)
+        (match_dup SFBOOL2_TMP_VSX_V4SI)))
+
+   ;; XXSPLTW t,r,r,1
+   (set (match_dup SFBOOL2_SPLAT_D)
+       (vec_duplicate:V4SI
+        (vec_select:SI
+         (match_dup SFBOOL2_TMP_VSX_V4SI)
+         (parallel [(match_dup SFBOOL2_XXSPLTW)]))))]
+{
+  rtx mfvsr_d = operands[SFBOOL2_MFVSR_D];
+  rtx bool_a1 = operands[SFBOOL2_BOOL_A1];
+  rtx bool_a2 = operands[SFBOOL2_BOOL_A2];
+  rtx bool_arg = (rtx_equal_p (mfvsr_d, bool_a1) ? bool_a2 : bool_a1);
+  int regno_mfvsr_a = REGNO (operands[SFBOOL2_MFVSR_A]);
+  int regno_tmp_vsx = REGNO (operands[SFBOOL2_TMP_VSX_V4SI]);
+
+  /* If the logical operation is a constant, form the constant in a vector
+     register.  */
+  if (CONST_INT_P (bool_arg))
+    {
+      HOST_WIDE_INT value = INTVAL (bool_arg);
+
+      /* See if we can directly load the constant, either by VSPLTIW or by
+         XXSPLTIW on power10.  */
+
+      if (IN_RANGE (value, -16, 15) || TARGET_PREFIXED)
+       {
+         rtvec cv = gen_rtvec (4, bool_arg, bool_arg, bool_arg, bool_arg);
+         operands[SFBOOL2_MTVSR_D] = gen_rtx_REG (V4SImode, regno_tmp_vsx);
+         operands[SFBOOL2_MTVSR_A] = gen_rtx_CONST_VECTOR (V4SImode, cv);
+       }
+
+      else
+       {
+         /* We need to load up the constant to a GPR and move it to a
+            vector register.  */
+         rtx tmp_gpr = operands[SFBOOL2_TMP_GPR_SI];
+         emit_move_insn (tmp_gpr, bool_arg);
+         operands[SFBOOL2_MTVSR_D] = gen_rtx_REG (SImode, regno_tmp_vsx);
+         operands[SFBOOL2_MTVSR_A] = tmp_gpr;
+       }
+    }
+  else
+    {
+      /* Mask is in a register, move it to a vector register.  */
+      operands[SFBOOL2_MTVSR_D] = gen_rtx_REG (SImode, regno_tmp_vsx);
+      operands[SFBOOL2_MTVSR_A] = bool_arg;
+    }
+
+    operands[SFBOOL2_TMP_VSX_V4SI] = gen_rtx_REG (V4SImode, regno_tmp_vsx);
+    operands[SFBOOL2_MFVSR_A_V4SI] = gen_rtx_REG (V4SImode, regno_mfvsr_a);
+    operands[SFBOOL2_XXSPLTW] = GEN_INT (BYTES_BIG_ENDIAN ? 1 : 2);
+})
+
 ;; Support signed/unsigned long long to float conversion vectorization.
 ;; Note that any_float (pc) here is just for code attribute <su>.
 (define_expand "vec_pack<su>_float_v2di"
diff --git a/gcc/testsuite/gcc.target/powerpc/pr108958.c 
b/gcc/testsuite/gcc.target/powerpc/pr108958.c
new file mode 100644
index 000000000000..21b3f2766918
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr108958.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target int128 } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-mdejagnu-cpu=power9 -O2" } */
+
+#ifndef TYPE
+#define TYPE unsigned long long
+#endif
+
+/* PR target/108958, when zero extending a DImode to a TImode, and the TImode 
variable is in a VSX register, generate:
+
+       mtvsrdd vreg,0,gpr
+
+   instead of:
+
+       mr tmp,gpr
+       li tmp+1,0
+       mtvsrdd vreg,tmp+1,tmp.  */
+
+void
+gpr_to_vsx (TYPE x, __uint128_t *p)
+{
+  /* mtvsrdd 0,0,3
+     stvx 0,0(4)  */
+
+  __uint128_t y = x;
+  __asm__ (" # %x0" : "+wa" (y));
+  *p = y;
+}
+
+void
+gpr_to_gpr (TYPE x, __uint128_t *p)
+{
+  /* mr 2,3
+     li 3,0
+     std 2,0(4)
+     std 3,8(4)  */
+
+  __uint128_t y = x;
+  __asm__ (" # %0" : "+r" (y));
+  *p = y;
+}
+
+/* { dg-final { scan-assembler-times {\mli\M}              1 } } */
+/* { dg-final { scan-assembler-times {\mmtvsrdd .*,0,.*\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mstd\M}             2 } } */
+/* { dg-final { scan-assembler-times {\mstxv\M}            1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/pr117487.c 
b/gcc/testsuite/gcc.target/powerpc/pr117487.c
new file mode 100644
index 000000000000..80d2bc169143
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr117487.c
@@ -0,0 +1,67 @@
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-mdejagnu-cpu=power9 -O2" } */
+/* { dg-require-effective-target powerpc_vsx } */
+
+#include <stdint.h>
+
+/*
+ * PR target/117487
+ *
+ * On power8 with the optimization it generates:
+ *
+ *     xscvdpspn 0,1
+ *     sldi 9,4,32
+ *     mtvsrd 32,9
+ *     xxland 1,0,32
+ *     xscvspdpn 1,1
+ *
+ * I.e., it converts the SFmode to the memory format (instead of the DFmode
+ * that is used within the register), converts the mask so that it is in the
+ * vector register in the upper 32-bits, and does a XXLAND (i.e. there is only
+ * one direct move from GPR to vector register).  Then after doing this, it
+ * converts the upper 32-bits back to DFmode.
+ *
+ * If the XSCVSPDN instruction took the value in the normal 32-bit scalar in a
+ * vector register, we wouldn't have needed the SLDI of the mask.
+ *
+ * On power9/power10/power11 before the fix wa applied, GCC generated:
+ *
+ *     xscvdpspn 0,1
+ *     mfvsrwz 2,0
+ *     and 2,2,4
+ *     mtvsrws 1,2
+ *     xscvspdpn 1,1
+ *     blr
+ *
+ * I.e convert to SFmode representation, move the value to a GPR, do an AND
+ * operation, move the 32-bit value with a splat, and then convert it back to
+ * DFmode format.
+ *
+ * After the patch was applied, it now generates:
+ *
+ *     xscvdpspn 0,1
+ *     mtvsrwz 32,2
+ *     xxland 32,0,32
+ *     xxspltw 1,32,1
+ *     xscvspdpn 1,1
+ *     blr
+ */
+
+union u {
+  float f;
+  uint32_t u32;
+};
+
+float
+math_foo (float x, unsigned int mask)
+{
+  union u arg;
+
+  arg.f = x;
+  arg.u32 &= mask;
+  return arg.f;
+}
+
+/* { dg-final { scan-assembler     {\mxxland\M} } } */
+/* { dg-final { scan-assembler-not {\mmfvsr}    } } */
+/* { dg-final { scan-assembler-not {\mand\M}    } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/pr120528.c 
b/gcc/testsuite/gcc.target/powerpc/pr120528.c
new file mode 100644
index 000000000000..476725eaa4fb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr120528.c
@@ -0,0 +1,91 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target int128 } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-require-effective-target power10_ok } */
+/* { dg-options "-mdejagnu-cpu=power10 -O2" } */
+
+#include <stddef.h>
+
+#ifndef TYPE
+#define TYPE unsigned long long
+#endif
+
+void
+mem_to_vsx (TYPE *p, __uint128_t *q)
+{
+  /* lxvrdx 0,0,3
+     stxv 0,0(4)  */
+
+  __uint128_t x = *p;
+  __asm__ (" # %x0" : "+wa" (x));
+  *q = x;
+}
+
+void
+memx_to_vsx (TYPE *p, size_t n, __uint128_t *q)
+{
+  /* sldi 4,4,3
+     lxvrdx 0,3,4
+     stxv 0,0(4)  */
+
+  __uint128_t x = p[n];
+  __asm__ (" # %x0" : "+wa" (x));
+  *q = x;
+}
+
+void
+mem3_to_vsx (TYPE *p, __uint128_t *q)
+{
+  /* addi 2,3,24
+     lxvrdx 0,0,2
+     stxv 0,0(4)  */
+
+  __uint128_t x = p[3];
+  __asm__ (" # %x0" : "+wa" (x));
+  *q = x;
+}
+
+void
+mem_to_gpr (TYPE *p, __uint128_t *q)
+{
+  /* ld 2,0(3)
+     li 3,0
+     std 2,0(4)
+     std 3,8(8)  */
+
+  __uint128_t x = *p;
+  __asm__ (" # %0" : "+r" (x));
+  *q = x;
+}
+
+void
+memx_to_gpr (TYPE *p, size_t n, __uint128_t *q)
+{
+  /* sldi 4,4,3
+     ldx 2,3,4
+     li 3,0
+     std 2,0(4)
+     std 3,8(8)  */
+
+  __uint128_t x = p[n];
+  __asm__ (" # %0" : "+r" (x));
+  *q = x;
+}
+
+void
+mem3_to_gpr (TYPE *p, __uint128_t *q)
+{
+  /* ld 2,24(3)
+     li 3,0
+     std 2,0(4)
+     std 3,8(8)  */
+
+  __uint128_t x = p[3];
+  __asm__ (" # %0" : "+r" (x));
+  *q = x;
+}
+
+/* { dg-final { scan-assembler-times {\maddi\M}   1 } } */
+/* { dg-final { scan-assembler-times {\mli\M}     3 } } */
+/* { dg-final { scan-assembler-times {\mlxvrdx\M} 3 } } */
+/* { dg-final { scan-assembler-times {\mstxv\M}   3 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/pr120681.c 
b/gcc/testsuite/gcc.target/powerpc/pr120681.c
new file mode 100644
index 000000000000..d883d1c8a951
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr120681.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_elfv2 } */
+/* { dg-require-effective-target powerpc_pcrel } */
+/* { dg-options "-mdejagnu-cpu=power10 -O2 -mcmodel=large" } */
+
+/* PR target/120681 -- verify that -mcpu=power10 -mcmodel=large uses PC
+   relative addressing instead of using TOC addressing.  */
+
+#ifndef TYPE
+#define TYPE unsigned long
+#endif
+
+extern TYPE global_var;
+
+void
+set_global (TYPE value)
+{
+  /*
+   * Generate:
+   * pld 9,global_var@got@pcrel
+   * std 3,0(9)
+   *
+   * Not:
+   * addis 9,2,.LC0@toc@ha
+   * ld    9,.LC0@toc@l(9)
+   * std   3,0(9)
+   */
+
+  global_var = value;
+}
+
+/* { dg-final { scan-assembler     {@got@pcrel} } } */
+/* { dg-final { scan-assembler-not {@toc@ha}    } } */
+/* { dg-final { scan-assembler-not {@toc@l}     } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/pr99293.c 
b/gcc/testsuite/gcc.target/powerpc/pr99293.c
new file mode 100644
index 000000000000..20adc1f27f65
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr99293.c
@@ -0,0 +1,22 @@
+/* { dg-do compile { target powerpc*-*-* } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O2 -mvsx" } */
+
+/* Test for PR 99263, which wants to do:
+       __builtin_vec_splats (__builtin_vec_extract (v, n))
+
+   where v is a V2DF or V2DI vector and n is either 0 or 1.  Previously the
+   compiler would do a direct move to the GPR registers to select the item and 
a
+   direct move from the GPR registers to do the splat.  */
+
+vector long long splat_dup_l_0 (vector long long v)
+{
+  return __builtin_vec_splats (__builtin_vec_extract (v, 0));
+}
+
+vector long long splat_dup_l_1 (vector long long v)
+{
+  return __builtin_vec_splats (__builtin_vec_extract (v, 1));
+}
+
+/* { dg-final { scan-assembler-times "xxpermdi" 2 } } */

Reply via email to