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 } } */
