@@ -4106,7 +4106,7 @@ riscv_output_move (rtx dest, rtx src)
switch (width)
{
case 2:
- if (TARGET_ZFHMIN)
+ if (TARGET_ZFHMIN || TARGET_ZFBFMIN)
return "fmv.x.h\t%0,%1";
/* Using fmv.x.s + sign-extend to emulate fmv.x.h. */
return "fmv.x.s\t%0,%1;slli\t%0,%0,16;srai\t%0,%0,16";
@@ -4162,7 +4162,7 @@ riscv_output_move (rtx dest, rtx src)
switch (width)
{
case 2:
- if (TARGET_ZFHMIN)
+ if (TARGET_ZFHMIN || TARGET_ZFBFMIN)
return "fmv.h.x\t%0,%z1";
/* High 16 bits should be all-1, otherwise HW will treated
as a n-bit canonical NaN, but isn't matter for softfloat. */
@@ -1763,6 +1763,57 @@
[(set_attr "type" "fcvt")
(set_attr "mode" "HF")])
+(define_insn "truncsfbf2"
+ [(set (match_operand:BF 0 "register_operand" "=f")
+ (float_truncate:BF
+ (match_operand:SF 1 "register_operand" " f")))]
+ "TARGET_ZFBFMIN"
+ "fcvt.bf16.s\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "BF")])
+
+;; The conversion of HF/DF/TF to BF needs to be done with SF if there is a
+;; chance to generate at least one instruction, otherwise just using
+;; libfunc __trunc[h|d|t]fbf2.
+(define_expand "trunchfbf2"
+ [(set (match_operand:BF 0 "register_operand" "=f")
+ (float_truncate:BF
+ (match_operand:HF 1 "register_operand" " f")))]
+ "TARGET_ZFBFMIN"
+ {
+ convert_move (operands[0],
+ convert_modes (SFmode, HFmode, operands[1], 0), 0);
+ DONE;
+ }
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "BF")])
+
+(define_expand "truncdfbf2"
+ [(set (match_operand:BF 0 "register_operand" "=f")
+ (float_truncate:BF
+ (match_operand:DF 1 "register_operand" " f")))]
+ "TARGET_ZFBFMIN"
+ {
+ convert_move (operands[0],
+ convert_modes (SFmode, DFmode, operands[1], 0), 0);
+ DONE;
+ }
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "BF")])
+
+(define_expand "trunctfbf2"
+ [(set (match_operand:BF 0 "register_operand" "=f")
+ (float_truncate:BF
+ (match_operand:TF 1 "register_operand" " f")))]
+ "TARGET_ZFBFMIN"
+ {
+ convert_move (operands[0],
+ convert_modes (SFmode, TFmode, operands[1], 0), 0);
+ DONE;
+ }
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "BF")])
+
;;
;; ....................
;;
@@ -1907,6 +1958,15 @@
[(set_attr "type" "fcvt")
(set_attr "mode" "SF")])
+(define_insn "extendbfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float_extend:SF
+ (match_operand:BF 1 "register_operand" " f")))]
+ "TARGET_ZFBFMIN"
+ "fcvt.s.bf16\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "SF")])
+
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float_extend:DF
@@ -1936,16 +1996,17 @@
DONE;
})
-(define_insn "*movhf_hardfloat"
- [(set (match_operand:HF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*f,*r, *r,*r,*m")
- (match_operand:HF 1 "move_operand" " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
- "TARGET_ZFHMIN
- && (register_operand (operands[0], HFmode)
- || reg_or_0_operand (operands[1], HFmode))"
+(define_insn "*mov<mode>_hardfloat"
+ [(set (match_operand:HFBF 0 "nonimmediate_operand" "=f, f,f,f,m,m,*f,*r, *r,*r,*m")
+ (match_operand:HFBF 1 "move_operand" " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
+ "((TARGET_ZFHMIN && <MODE>mode == HFmode)
+ || (TARGET_ZFBFMIN && <MODE>mode == BFmode))
+ && (register_operand (operands[0], <MODE>mode)
+ || reg_or_0_operand (operands[1], <MODE>mode))"
{ return riscv_output_move (operands[0], operands[1]); }
[(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
(set_attr "type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
- (set_attr "mode" "HF")])
+ (set_attr "mode" "<MODE>")])
(define_insn "*mov<mode>_softfloat"
[(set (match_operand:HFBF 0 "nonimmediate_operand" "=f, r,r,m,*f,*r")
new file mode 100644
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i_zfbfmin -mabi=ilp32f -mcmodel=medany -O" { target { rv32 } } } */
+/* { dg-options "-march=rv64i_zfbfmin -mabi=lp64f -mcmodel=medany -O" { target { rv64 } } } */
+
+/* 1) bf -> sf fcvt.s.bf16 */
+/* 2) sf1 [+|-|*|/] sf2 f[add|sub|mul|div].s */
+/* 3) sf -> bf fcvt.bf16.s */
+extern __bf16 bf;
+extern __bf16 bf1;
+extern __bf16 bf2;
+
+void bf_add_bf () { bf = bf1 + bf2; }
+
+void bf_sub_bf () { bf = bf1 - bf2; }
+
+void bf_mul_bf () { bf = bf1 * bf2; }
+
+void bf_div_bf () { bf = bf1 / bf2; }
+
+void bf_add_const () { bf = bf1 + 3.14f; }
+
+void const_sub_bf () { bf = 3.14f - bf2; }
+
+void bf_mul_const () { bf = bf1 * 3.14f; }
+
+void const_div_bf () { bf = 3.14f / bf2; }
+
+void bf_inc () { ++bf; }
+
+void bf_dec () { --bf; }
+
+/* { dg-final { scan-assembler-times "fcvt.s.bf16" 14 } } */
+/* { dg-final { scan-assembler-times "fcvt.bf16.s" 10 } } */
+
+/* { dg-final { scan-assembler-not "call" } } */
new file mode 100644
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i_zfbfmin -mabi=ilp32f -O" { target { rv32 } } } */
+/* { dg-options "-march=rv64i_zfbfmin -mabi=lp64f -O" { target { rv64 } } } */
+
+/* 1) bf -> sf fcvt.s.bf16 */
+/* 2) sf1 [<|<=|>|>=|==] sf2 f[lt|le|gt|ge|eq].s */
+extern __bf16 bf;
+extern __bf16 bf1;
+extern __bf16 bf2;
+
+void bf_lt_bf () { bf = (bf1 < bf2) ? bf1 : bf2; }
+
+void bf_le_bf () { bf = (bf1 <= bf2) ? bf1 : bf2; }
+
+void bf_gt_bf () { bf = (bf1 > bf2) ? bf1 : bf2; }
+
+void bf_ge_bf () { bf = (bf1 >= bf2) ? bf1 : bf2; }
+
+void bf_eq_bf () { bf = (bf1 == bf2) ? bf1 : bf2; }
+
+void bf_lt_const () { bf = (bf1 < 3.14f) ? bf1 : bf2; }
+
+void bf_le_const () { bf = (bf1 <= 3.14f) ? bf1 : bf2; }
+
+void const_gt_bf () { bf = (3.14f > bf2) ? bf1 : bf2; }
+
+void const_ge_bf () { bf = (3.14f >= bf2) ? bf1 : bf2; }
+
+void bf_eq_const () { bf = (bf1 == 3.14f) ? bf1 : bf2; }
+
+/* { dg-final { scan-assembler-times "fcvt.s.bf16" 15 } } */
+
+/* { dg-final { scan-assembler-not "call" } } */
new file mode 100644
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i_zfbfmin -mabi=ilp32f -O" { target { rv32 } } } */
+/* { dg-options "-march=rv64i_zfbfmin -mabi=lp64f -O" { target { rv64 } } } */
+
+
+/* 1) float -> BF16
+ * hf -> bf == hf -> sf -> bf fcvt.h.s + fcvt.bf16.s
+ * sf -> bf == sf -> bf fcvt.bf16.s
+ * df -> bf == df -> sf -> bf __truncdfsf2 + fcvt.bf16.s
+ * tf -> bf == tf -> sf -> bf __trunctfsf2 + fcvt.bf16.s
+*/
+
+/* 2) BF16 -> float
+ * bf -> hf == bf -> sf -> hf fcvt.s.bf16 + fcvt.s.h
+ * bf -> sf == bf -> sf fcvt.s.bf16
+ * bf -> df == bf -> sf -> df fcvt.s.bf16 + __extendsfdf2
+ * bf -> tf == bf -> sf -> tf fcvt.s.bf16 + __extendsftf2
+*/
+
+extern __bf16 bf;
+extern _Float16 hf;
+extern float sf;
+extern double df;
+extern long double tf;
+
+void hf_to_bf () { bf = hf; }
+void bf_to_hf () { hf = bf; }
+
+void sf_to_bf () { bf = sf; }
+void bf_to_sf () { sf = bf; }
+
+void df_to_bf () { bf = df; }
+void bf_to_df () { df = bf; }
+
+void tf_to_bf () { bf = tf; }
+void bf_to_tf () { tf = bf; }
+
+/* { dg-final { scan-assembler-times "fcvt.bf16.s" 4 } } */
+/* { dg-final { scan-assembler-times "fcvt.s.bf16" 4 } } */
+/* { dg-final { scan-assembler-times "fcvt.h.s" 1 } } */
+/* { dg-final { scan-assembler-times "fcvt.s.h" 1 } } */
+/* { dg-final { scan-assembler-times "call\t__truncdfsf2" 1 } } */
+/* { dg-final { scan-assembler-times "call\t__trunctfsf2" 1 } } */
+/* { dg-final { scan-assembler-times "call\t__extendsfdf2" 1 } } */
+/* { dg-final { scan-assembler-times "call\t__extendsftf2" 1 } } */
new file mode 100644
@@ -0,0 +1,66 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i_zfbfmin -mabi=ilp32f -O" { target { rv32 } } } */
+/* { dg-options "-march=rv64i_zfbfmin -mabi=lp64f -O" { target { rv64 } } } */
+
+/* 1) Integer -> BF16
+ * qi/hi -> bf fcvt.s.w + fcvt.bf16.s
+ * uqi/uhi -> bf fcvt.s.wu + fcvt.bf16.s
+ *
+ * si/di/ti -> bf __float[s|d|t]ibf
+ * usi/udi/uti -> bf __floatun[s|d|t]ibf
+*/
+
+/* 2) BF16 -> Integer
+ * bf -> qi/hi/si/di fcvt.s.bf16 + fcvt.[w|l].s
+ * bf -> uqi/uhi/usi/udi fcvt.s.bf16 + fcvt.[w|l]u.s
+ * bf -> ti/uti fcvt.s.bf16 + __fix[uns]sfti
+*/
+
+extern __bf16 bf;
+
+extern signed char qi;
+extern unsigned char uqi;
+extern signed short hi;
+extern unsigned short uhi;
+extern signed int si;
+extern unsigned int usi;
+extern signed long long di;
+extern unsigned long long udi;
+
+void qi_to_bf () { bf = qi; }
+void uqi_to_bf () { bf = uqi; }
+void bf_to_qi () { qi = bf; }
+void bf_to_uqi () { uqi = bf; }
+
+void hi_to_bf () { bf = hi; }
+void uhi_to_bf () { bf = uhi; }
+void bf_to_hi () { hi = bf; }
+void bf_to_uhi () { uhi = bf; }
+
+void si_to_bf () { bf = si; }
+void usi_to_bf () { bf = usi; }
+void bf_to_si () { si = bf; }
+void bf_to_usi () { usi = bf; }
+
+void di_to_bf () { bf = di; }
+void udi_to_bf () { bf = udi; }
+void bf_to_di () { di = bf; }
+void bf_to_udi () { udi = bf; }
+
+#if __riscv_xlen == 64
+extern signed __int128 ti;
+extern unsigned __int128 uti;
+void ti_to_bf () { bf = ti; } /* { dg-final { scan-assembler-times "call\t__floattibf" 1 { target { rv64 } } } } */
+void uti_to_bf () { bf = uti; } /* { dg-final { scan-assembler-times "call\t__floatuntibf" 1 { target { rv64 } } } } */
+void bf_to_ti () { ti = bf; } /* { dg-final { scan-assembler-times "call\t__fixsfti" 1 { target { rv64 } } } } */
+void bf_to_uti () { uti = bf; } /* { dg-final { scan-assembler-times "call\t__fixunssfti" 1 { target { rv64 } } } } */
+#endif
+
+/* { dg-final { scan-assembler-times "fcvt.bf16.s" 4 } } */
+/* { dg-final { scan-assembler-times "fcvt.s.bf16" 8 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "fcvt.s.bf16" 10 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__floatsibf" 1 } } */
+/* { dg-final { scan-assembler-times "call\t__floatunsibf" 1 } } */
+/* { dg-final { scan-assembler-times "call\t__floatdibf" 1 } } */
+/* { dg-final { scan-assembler-times "call\t__floatundibf" 1 } } */