https://gcc.gnu.org/g:0a91f1db49791101e9ecd13dbd4820240e737e02
commit 0a91f1db49791101e9ecd13dbd4820240e737e02 Author: Michael Meissner <[email protected]> Date: Sat Oct 17 01:37:38 2026 -0400 Add bfloat16 define_peephole2. 2026-10-17 Michael Meissner <[email protected]> * config/rs6000/float16.md (bfloat16 define_peephole2): Add a peephole2 to try to catch some cases where bfloat16 uses vector V4SFmode arithmetic for some things and then converts the value to scalar SFmode for other calculations. * config/rs6000/rs6000.opt (-mfloat16-peephole2): New debug switch. Diff: --- gcc/config/rs6000/float16.md | 138 +++++++++++++++++++++++++++++++++++++++++++ gcc/config/rs6000/rs6000.opt | 4 ++ 2 files changed, 142 insertions(+) diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md index d3a31791f9bc..fd9039b465db 100644 --- a/gcc/config/rs6000/float16.md +++ b/gcc/config/rs6000/float16.md @@ -1524,3 +1524,141 @@ operands[3], FP16_NFMS); DONE; }) + + +;; Peephole2 to try and catch some conversions from V4SFmode to SFmode, +;; do an operation in SFmode and convert it V4SFmode. +;; +;; During testing, it was discovered that sometimes we optimized some +;; calculations to use the vector format, while others forced the +;; calculation to use scalar values. + +(define_peephole2 + [(match_scratch:V4SF 0 "wa") ;; tmp + + ;; Convert a vector V4SFmode operation back to scalar SFmode. + (set (match_operand:SF 1 "vsx_register_operand") + (unspec:SF [(match_operand:V4SF 2 "vsx_register_operand")] + UNSPEC_VSX_CVSPDP)) + + ;; Do an operation in scalar SFmode. + (set (match_operand:SF 3 "vsx_register_operand") + (match_operator:SF 4 "fp16_binary_operator" + [(match_operand:SF 5 "vsx_register_operand") + (match_operand:SF 6 "vsx_register_operand")])) + + ;; Convert the scalar result back to vector. + (set (match_operand:V4SF 7 "vsx_register_operand") + (unspec:V4SF [(match_dup 3)] + UNSPEC_VSX_CVSPDP)) + + ;; Make sure the temporary register are live through this point. + (match_dup 0) + (match_dup 5) + (match_dup 6) + + ;; Convert the result to BFmode. + (set (match_operand:BF 8 "vsx_register_operand") + (unspec:BF [(match_dup 7)] UNSPEC_XVCVSPBF16_BF))] + + "TARGET_FLOAT16_PEEPHOLE2 && TARGET_BFLOAT16_HW + && (rtx_equal_p (operands[1], operands[5]) + || rtx_equal_p (operands[1], operands[6])) + && (peep2_reg_dead_p (2, operands[1]) + || reg_or_subregno (operands[1]) == reg_or_subregno (operands[3])) + && (peep2_reg_dead_p (3, operands[3]) + || reg_or_subregno (operands[3]) == reg_or_subregno (operands[7])) + && (peep2_reg_dead_p (4, operands[7]) + || reg_or_subregno (operands[7]) == reg_or_subregno (operands[8]))" + + ;; Convert the other scalar argument to vector form. + [(match_dup 9) + + ;; Do the operation in vector mode. + (set (match_dup 7) + (match_dup 10)) + + ;; Convert the result to BFmode. + (set (match_dup 8) + (unspec:BF[(match_dup 7)] UNSPEC_XVCVSPBF16_BF))] + +{ + rtx tmp = operands[0]; // temporary + rtx scalar = operands[1]; // conversion from V4SF output + rtx vin = operands[2]; // V4SF before conversion to scalar + rtx sop = operands[4]; // SF binary operation + rtx sarg1 = operands[5]; // SF binary arg1 + rtx sarg2 = operands[6]; // SF binary arg2 + rtx varg1, varg2; // vector inputs + + unsigned int scalar_reg = reg_or_subregno (scalar); + unsigned int sarg1_reg = reg_or_subregno (sarg1); + unsigned int sarg2_reg = reg_or_subregno (sarg2); + +#ifdef TARGET_DEBUG_EXTRA1 + if (TARGET_DEBUG_EXTRA1) + { + fprintf (stderr, "\n========== Bfloat16 peephole2 input insns\n\n"); + debug_rtx (gen_rtx_CLOBBER (VOIDmode, tmp)); + debug_rtx (gen_vsx_xscvspdp_scalar2 (scalar, vin)); + debug_rtx (gen_rtx_SET (operands[3], operands[4])); + debug_rtx (gen_vsx_xscvdpsp_scalar (operands[7], operands[3])); + debug_rtx (gen_xvcvspbf16_bf (operands[8], operands[7])); + } +#endif + + /* + * Create the vector operation. We convert the scalar argument that + * was not the result of a vector to scalar operation to being a + * vector value. + */ + + /* + * Both scalar registers are the same. The move is a NOP and it + * will be deleted. + */ + + if (scalar_reg == sarg1_reg && scalar_reg == sarg2_reg) + { + varg1 = vin; + varg2 = vin; + operands[9] = gen_rtx_SET (vin, vin); + } + + /* The converted scalar reg is arg1, convert arg2 to vector. */ + else if (scalar_reg == sarg1_reg) + { + varg1 = vin; + varg2 = tmp; + operands[9] = gen_vsx_xscvdpsp (tmp, + gen_rtx_REG (DFmode, sarg2_reg)); + } + + /* The converted scalar reg is arg2, convert arg1 to vector. */ + else if (scalar_reg == sarg2_reg) + { + varg1 = tmp; + varg2 = vin; + operands[9] = gen_vsx_xscvdpsp (tmp, + gen_rtx_REG (DFmode, sarg1_reg)); + } + + else + gcc_unreachable (); + + /* Create the vector binary operation operations instead of using scalar. */ + operands[10] = gen_rtx_fmt_ee (GET_CODE (sop), V4SFmode, varg1, varg2); + +#ifdef TARGET_DEBUG_EXTRA1 + if (TARGET_DEBUG_EXTRA1) + { + fprintf (stderr, "\n========== Bfloat16 peephole2 output insns\n\n"); + debug_rtx (operands[9]); + debug_rtx (gen_rtx_SET (operands[7], operands[10])); + debug_rtx (gen_xvcvspbf16_bf (operands[8], operands[7])); + fprintf (stderr, "\n========== Bfloat16 peephole2 done\n\n"); + } +#endif +}) + + diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt index 973051afc350..893c8a3dfcf2 100644 --- a/gcc/config/rs6000/rs6000.opt +++ b/gcc/config/rs6000/rs6000.opt @@ -650,6 +650,10 @@ mfloat16-gpr-convert Target Undocumented Var(TARGET_FLOAT16_GPR_CONVERT) Init(1) Save Pass/return (do not pass/return) 16-it float conversions in GPR registers. +mfloat16-peephole2 +Target Undocumented Var(TARGET_FLOAT16_PEEPHOLE2) Init(1) Save +Enable/disble peephole2 processing. + ; Documented parameters -param=rs6000-vect-unroll-limit=
