https://gcc.gnu.org/g:d2b2c6fb4d7f96d8319492a512a69278bdbb9073
commit d2b2c6fb4d7f96d8319492a512a69278bdbb9073 Author: Michael Meissner <[email protected]> Date: Fri Oct 16 16:51:05 2026 -0400 Work on using vector insns to do BFmode operations. 2026-10-15 Michael Meissner <[email protected]> * config/rs6000/float16.cc (toplevel): Include emit-rtl.h. (bfloat16_operation_as_v4sf_inner): Use vslw if we are loading the value. Try to improve constant handling. * config/rs6000/float16.md (bf_shift_left): New insn. * config/rs6000/predicates.md (easy_vector_constant_add_self): Generate xxspltib on power9 rather than issuing 2 altivec instructions. (easy_vector_constant_msb): Likewise. (easy_vector_constant_vsldoi): Likewise. (bfloat16_v4sf_operand): Rework code. Diff: --- gcc/config/rs6000/float16.cc | 74 +++++++++++++++++++++++++++++------------ gcc/config/rs6000/float16.md | 18 ++++++++++ gcc/config/rs6000/predicates.md | 41 ++++++++++++----------- 3 files changed, 92 insertions(+), 41 deletions(-) diff --git a/gcc/config/rs6000/float16.cc b/gcc/config/rs6000/float16.cc index e5206b910694..5a7317525396 100644 --- a/gcc/config/rs6000/float16.cc +++ b/gcc/config/rs6000/float16.cc @@ -39,6 +39,7 @@ #include "attribs.h" #include "explow.h" #include "expr.h" +#include "emit-rtl.h" #include "common/common-target.h" #include "rs6000-internal.h" @@ -264,43 +265,74 @@ bfloat16_operation_as_v4sf_inner (enum rtx_code icode, break; } - /* Convert operands to V4SFmode format. We use SPLAT for registers to - get the value into the upper 32-bits. We can use XXSPLTW to splat - words instead of VSPLTIH since the XVCVBF16SPN instruction ignores the - odd half-words, and XXSPLTW can operate on all VSX registers instead - of just the Altivec registers. Using SPLAT instead of a shift also - insure that other bits are not a signalling NaN. If we are using - XXSPLTIW or XXSPLTIB to load the constant the other bits are - duplicated. */ + /* Convert operands to V4SFmode format. + + We use SPLAT for registers to get the value into the upper 32-bits. + We can use XXSPLTW to splat words instead of VSPLTIH since the + XVCVBF16SPN instruction ignores the odd half-words, and XXSPLTW can + operate on all VSX registers instead of just the Altivec registers. + Using SPLAT instead of a shift also insure that other bits are not a + signalling NaN. If we are using XXSPLTIW or XXSPLTIB to load the + constant the other bits are duplicated. + + However, if we are loading up the value from memory, we know the other + bits will all be 0, so we can do a vslw to get the 16-bit BFmode value + into the position that xvcvspbf16 will use to create the BFmode + value after the operation. */ rtx tmp = ops_v4sf[i] = gen_reg_rtx (V4SFmode); if (op == CONST0_RTX (SFmode) || op == CONST0_RTX (BFmode)) emit_move_insn (tmp, CONST0_RTX (V4SFmode)); - else if (GET_MODE (op) == BFmode) + else if (CONST_DOUBLE_P (op)) { - emit_insn (gen_xxspltw_bf (tmp, force_reg (BFmode, op))); - emit_insn (gen_xvcvbf16spn_bf (tmp, tmp)); + rtx sf_op; + + if (GET_MODE (op) == SFmode) + sf_op = op; + else + { + const REAL_VALUE_TYPE *rtype = CONST_DOUBLE_REAL_VALUE (op); + sf_op = const_double_from_real_value (*rtype, SFmode); + } + + rtvec v = gen_rtvec (4, sf_op, sf_op, sf_op, sf_op); + rtx cv = gen_rtx_CONST_VECTOR (V4SFmode, v); + rtx insn = emit_insn (gen_rtx_SET (tmp, cv)); + set_unique_reg_note (insn, REG_EQUIV, cv); } - else if (GET_MODE (op) == SFmode) + else if (GET_MODE (op) == BFmode) { - if (GET_CODE (op) == CONST_DOUBLE) + rtx op_reg = force_reg (BFmode, op); + + if (MEM_P (op)) { - rtvec v = rtvec_alloc (4); + rtx s = GEN_INT (16); + rtvec shift_vec = gen_rtvec (16, + s, s, s, s, s, s, s, s, + s, s, s, s, s, s, s, s); - for (size_t i = 0; i < 4; i++) - RTVEC_ELT (v, i) = op; + rtx shift = gen_rtx_CONST_VECTOR (V16QImode, shift_vec); + rtx tmp2 = gen_reg_rtx (V16QImode); - emit_insn (gen_rtx_SET (tmp, - gen_rtx_CONST_VECTOR (V4SFmode, v))); - } + rtx insn = emit_insn (gen_rtx_SET (tmp2, shift)); + set_unique_reg_note (insn, REG_EQUIV, shift); + emit_insn (gen_bf_shift_left (tmp, op_reg, tmp2)); + } else - emit_insn (gen_vsx_splat_v4sf (tmp, - force_reg (SFmode, op))); + { + rtx tmp2 = gen_reg_rtx (V4SFmode); + emit_insn (gen_xxspltw_bf (tmp2, op_reg)); + emit_insn (gen_xvcvbf16spn_bf (tmp, tmp2)); + } } + else if (GET_MODE (op) == SFmode) + emit_insn (gen_vsx_splat_v4sf (tmp, + force_reg (SFmode, op))); + else gcc_unreachable (); } diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md index d3a31791f9bc..696e2e1bd18d 100644 --- a/gcc/config/rs6000/float16.md +++ b/gcc/config/rs6000/float16.md @@ -1242,6 +1242,24 @@ "TARGET_BFLOAT16_HW" "xvcvbf16spn %x0,%x1" [(set_attr "type" "vecperm")]) + +(define_insn_and_split "bf_shift_left" + [(set (match_operand:V4SF 0 "altivec_register_operand" "=v") + (unspec:V4SF [(match_operand:BF 1 "altivec_register_operand" "v") + (match_operand:V16QI 2 "altivec_register_operand" "v")] + UNSPEC_CVT_FP16_TO_V4SF))] + "TARGET_BFLOAT16_HW" + "#" + "&& reload_completed" + [(set (match_dup 3) + (ashift:V4SI (match_dup 4) + (match_dup 5)))] +{ + operands[3] = gen_rtx_REG (V4SImode, reg_or_subregno (operands[0])); + operands[4] = gen_rtx_REG (V4SImode, reg_or_subregno (operands[1])); + operands[5] = gen_rtx_REG (V4SImode, reg_or_subregno (operands[2])); +} + [(set_attr "type" "vecsimple")]) ;; Optimize __bfloat16 binary operations. Unlike _Float16 where we ;; have instructions to convert between HFmode and SFmode as scalar diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index afe63447eb0d..873416f1f60f 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -820,6 +820,8 @@ int elt; if (mode == V2DImode || mode == V2DFmode) return 0; + if (TARGET_P9_VECTOR && xxspltib_constant_nosplit (op, mode)) + return false; elt = BYTES_BIG_ENDIAN ? GET_MODE_NUNITS (mode) - 1 : 0; val = const_vector_elt_as_int (op, elt); val = sext_hwi (val, 8); @@ -839,6 +841,8 @@ int isz = GET_MODE_SIZE (inner); if (mode == V2DImode || mode == V2DFmode) return 0; + if (TARGET_P9_VECTOR && xxspltib_constant_nosplit (op, mode)) + return false; elt = BYTES_BIG_ENDIAN ? GET_MODE_NUNITS (mode) - 1 : 0; if (isz < sz) { @@ -858,6 +862,7 @@ (and (match_code "const_vector") (and (match_test "TARGET_ALTIVEC") (and (match_test "easy_altivec_constant (op, mode)") + (match_test "!xxspltib_constant_nosplit (op, mode)") (match_test "vspltis_shifted (op) != 0"))))) ;; Return true if this is a vector constant and each byte in @@ -2320,6 +2325,9 @@ (define_predicate "bfloat16_v4sf_operand" (match_code "reg,subreg,const_double,float_extend,float_truncate,plus,minus,mult") { + rtx arg; + machine_mode arg_mode; + if (mode != BFmode && mode != SFmode) return false; @@ -2336,32 +2344,25 @@ return true; case FLOAT_EXTEND: - { - if (mode != SFmode) - return false; - - rtx arg = XEXP (op, 0); - machine_mode arg_mode = GET_MODE (arg); + if (mode != SFmode) + return false; - if (arg_mode != BFmode) - return false; + arg = XEXP (op, 0); + arg_mode = GET_MODE (arg); - if (MEM_P (arg)) - return true; + if (arg_mode != BFmode) + return false; - return register_operand (arg, arg_mode); - } + return register_operand (arg, arg_mode) || MEM_P (arg); case FLOAT_TRUNCATE: - { - if (mode != BFmode) - return false; + if (mode != BFmode) + return false; - rtx arg = XEXP (op, 0); - return (GET_MODE (arg) == SFmode - && GET_CODE (arg) == FLOAT_EXTEND - && GET_MODE (XEXP (arg, 0)) == BFmode); - } + arg = XEXP (op, 0); + return (GET_MODE (arg) == SFmode + && GET_CODE (arg) == FLOAT_EXTEND + && GET_MODE (XEXP (arg, 0)) == BFmode); /* Allow for chained operations. */ case PLUS:
