[gcc(refs/vendors/riscv/heads/gcc-14-with-riscv-opts)] [RISC-V] Add support for _Bfloat16

Jeff Law law@gcc.gnu.org
Tue May 7 17:49:31 GMT 2024


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

commit af9ec7bb55674b09434ff821ee496558ca8dc4c3
Author: Xiao Zeng <zengxiao@eswincomputing.com>
Date:   Mon May 6 15:39:12 2024 -0600

    [RISC-V] Add support for _Bfloat16
    
    1 At point <https://github.com/riscv/riscv-bfloat16>,
      BF16 has already been completed "post public review".
    
    2 LLVM has also added support for RISCV BF16 in
      <https://reviews.llvm.org/D151313> and
      <https://reviews.llvm.org/D150929>.
    
    3 According to the discussion <https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/367>,
      this use __bf16 and use DF16b in riscv_mangle_type like x86.
    
    Below test are passed for this patch
        * The riscv fully regression test.
    
    gcc/ChangeLog:
    
            * config/riscv/iterators.md: New mode iterator HFBF.
            * config/riscv/riscv-builtins.cc (riscv_init_builtin_types):
            Initialize data type _Bfloat16.
            * config/riscv/riscv-modes.def (FLOAT_MODE): New.
            (ADJUST_FLOAT_FORMAT): New.
            * config/riscv/riscv.cc (riscv_mangle_type): Support for BFmode.
            (riscv_scalar_mode_supported_p): Ditto.
            (riscv_libgcc_floating_mode_supported_p): Ditto.
            (riscv_init_libfuncs): Set the conversion method for BFmode and
            HFmode.
            (riscv_block_arith_comp_libfuncs_for_mode): Set the arithmetic
            and comparison libfuncs for the mode.
            * config/riscv/riscv.md (mode" ): Add BF.
            (movhf): Support for BFmode.
            (mov<mode>): Ditto.
            (*movhf_softfloat): Ditto.
            (*mov<mode>_softfloat): Ditto.
    
    libgcc/ChangeLog:
    
            * config/riscv/sfp-machine.h (_FP_NANFRAC_B): New.
            (_FP_NANSIGN_B): Ditto.
            * config/riscv/t-softfp32: Add support for BF16 libfuncs.
            * config/riscv/t-softfp64: Ditto.
            * soft-fp/floatsibf.c: For si -> bf16.
            * soft-fp/floatunsibf.c: For unsi -> bf16.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/bf16_arithmetic.c: New test.
            * gcc.target/riscv/bf16_call.c: New test.
            * gcc.target/riscv/bf16_comparison.c: New test.
            * gcc.target/riscv/bf16_float_libcall_convert.c: New test.
            * gcc.target/riscv/bf16_integer_libcall_convert.c: New test.
    
    Co-authored-by: Jin Ma <jinma@linux.alibaba.com>
    (cherry picked from commit 8c7cee80eb50792e57d514be1418c453ddd1073e)

Diff:
---
 gcc/config/riscv/iterators.md                      |  2 +
 gcc/config/riscv/riscv-builtins.cc                 | 16 +++++
 gcc/config/riscv/riscv-modes.def                   |  3 +
 gcc/config/riscv/riscv.cc                          | 64 +++++++++++------
 gcc/config/riscv/riscv.md                          | 24 +++----
 gcc/testsuite/gcc.target/riscv/bf16_arithmetic.c   | 42 +++++++++++
 gcc/testsuite/gcc.target/riscv/bf16_call.c         | 12 ++++
 gcc/testsuite/gcc.target/riscv/bf16_comparison.c   | 36 ++++++++++
 .../gcc.target/riscv/bf16_float_libcall_convert.c  | 57 +++++++++++++++
 .../riscv/bf16_integer_libcall_convert.c           | 81 ++++++++++++++++++++++
 libgcc/config/riscv/sfp-machine.h                  |  3 +
 libgcc/config/riscv/t-softfp32                     | 10 ++-
 libgcc/config/riscv/t-softfp64                     |  3 +-
 libgcc/soft-fp/floatsibf.c                         | 45 ++++++++++++
 libgcc/soft-fp/floatunsibf.c                       | 45 ++++++++++++
 15 files changed, 407 insertions(+), 36 deletions(-)

diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
index 75e119e407a3..32e1b1403051 100644
--- a/gcc/config/riscv/iterators.md
+++ b/gcc/config/riscv/iterators.md
@@ -75,6 +75,8 @@
 ;; Iterator for floating-point modes that can be loaded into X registers.
 (define_mode_iterator SOFTF [SF (DF "TARGET_64BIT") (HF "TARGET_ZFHMIN")])
 
+;; Iterator for floating-point modes of BF16
+(define_mode_iterator HFBF [HF BF])
 
 ;; -------------------------------------------------------------------
 ;; Mode attributes
diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc
index d457e306dd18..4c08834288ac 100644
--- a/gcc/config/riscv/riscv-builtins.cc
+++ b/gcc/config/riscv/riscv-builtins.cc
@@ -230,6 +230,7 @@ static GTY(()) int riscv_builtin_decl_index[NUM_INSN_CODES];
   riscv_builtin_decls[riscv_builtin_decl_index[(CODE)]]
 
 tree riscv_float16_type_node = NULL_TREE;
+tree riscv_bfloat16_type_node = NULL_TREE;
 
 /* Return the function type associated with function prototype TYPE.  */
 
@@ -273,6 +274,21 @@ riscv_init_builtin_types (void)
   if (!maybe_get_identifier ("_Float16"))
     lang_hooks.types.register_builtin_type (riscv_float16_type_node,
 					    "_Float16");
+
+  /* Provide the _Bfloat16 type and bfloat16_type_node if needed.  */
+  if (!bfloat16_type_node)
+    {
+      riscv_bfloat16_type_node = make_node (REAL_TYPE);
+      TYPE_PRECISION (riscv_bfloat16_type_node) = 16;
+      SET_TYPE_MODE (riscv_bfloat16_type_node, BFmode);
+      layout_type (riscv_bfloat16_type_node);
+    }
+  else
+    riscv_bfloat16_type_node = bfloat16_type_node;
+
+  if (!maybe_get_identifier ("_Bfloat16"))
+    lang_hooks.types.register_builtin_type (riscv_bfloat16_type_node,
+					    "_Bfloat16");
 }
 
 /* Implement TARGET_INIT_BUILTINS.  */
diff --git a/gcc/config/riscv/riscv-modes.def b/gcc/config/riscv/riscv-modes.def
index bdce89b17aae..6de4e4402989 100644
--- a/gcc/config/riscv/riscv-modes.def
+++ b/gcc/config/riscv/riscv-modes.def
@@ -21,6 +21,9 @@ along with GCC; see the file COPYING3.  If not see
 
 FLOAT_MODE (HF, 2, ieee_half_format);
 FLOAT_MODE (TF, 16, ieee_quad_format);
+FLOAT_MODE (BF, 2, 0);
+/* Reuse definition from arm.  */
+ADJUST_FLOAT_FORMAT (BF, &arm_bfloat_half_format);
 
 /* Vector modes.  */
 
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 6f1c67bf3f7a..545e68566dc7 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -10188,9 +10188,17 @@ riscv_asan_shadow_offset (void)
 static const char *
 riscv_mangle_type (const_tree type)
 {
-  /* Half-precision float, _Float16 is "DF16_".  */
+  /* Half-precision float, _Float16 is "DF16_" and _Bfloat16 is "DF16b".  */
   if (SCALAR_FLOAT_TYPE_P (type) && TYPE_PRECISION (type) == 16)
-    return "DF16_";
+    {
+      if (TYPE_MODE (type) == HFmode)
+	return "DF16_";
+
+      if (TYPE_MODE (type) == BFmode)
+	return "DF16b";
+
+      gcc_unreachable ();
+    }
 
   /* Mangle all vector type for vector extension.  */
   /* The mangle name follows the rule of RVV LLVM
@@ -10211,19 +10219,20 @@ riscv_mangle_type (const_tree type)
 static bool
 riscv_scalar_mode_supported_p (scalar_mode mode)
 {
-  if (mode == HFmode)
+  if (mode == HFmode || mode == BFmode)
     return true;
   else
     return default_scalar_mode_supported_p (mode);
 }
 
 /* Implement TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P - return TRUE
-   if MODE is HFmode, and punt to the generic implementation otherwise.  */
+   if MODE is HFmode or BFmode, and punt to the generic implementation
+   otherwise.  */
 
 static bool
 riscv_libgcc_floating_mode_supported_p (scalar_float_mode mode)
 {
-  if (mode == HFmode)
+  if (mode == HFmode || mode == BFmode)
     return true;
   else
     return default_libgcc_floating_mode_supported_p (mode);
@@ -10274,27 +10283,42 @@ riscv_floatn_mode (int n, bool extended)
   return default_floatn_mode (n, extended);
 }
 
+/* Record that we have no arithmetic or comparison libfuncs for
+   machine_mode MODE.  */
 static void
-riscv_init_libfuncs (void)
+riscv_block_arith_comp_libfuncs_for_mode (machine_mode mode)
 {
-  /* Half-precision float operations.  The compiler handles all operations
-     with NULL libfuncs by converting to SFmode.  */
+  /* Half-precision float or Brain float operations.  The compiler handles all
+     operations with NULL libfuncs by converting to SFmode.  */
 
   /* Arithmetic.  */
-  set_optab_libfunc (add_optab, HFmode, NULL);
-  set_optab_libfunc (sdiv_optab, HFmode, NULL);
-  set_optab_libfunc (smul_optab, HFmode, NULL);
-  set_optab_libfunc (neg_optab, HFmode, NULL);
-  set_optab_libfunc (sub_optab, HFmode, NULL);
+  set_optab_libfunc (add_optab, mode, NULL);
+  set_optab_libfunc (sdiv_optab, mode, NULL);
+  set_optab_libfunc (smul_optab, mode, NULL);
+  set_optab_libfunc (neg_optab, mode, NULL);
+  set_optab_libfunc (sub_optab, mode, NULL);
 
   /* Comparisons.  */
-  set_optab_libfunc (eq_optab, HFmode, NULL);
-  set_optab_libfunc (ne_optab, HFmode, NULL);
-  set_optab_libfunc (lt_optab, HFmode, NULL);
-  set_optab_libfunc (le_optab, HFmode, NULL);
-  set_optab_libfunc (ge_optab, HFmode, NULL);
-  set_optab_libfunc (gt_optab, HFmode, NULL);
-  set_optab_libfunc (unord_optab, HFmode, NULL);
+  set_optab_libfunc (eq_optab, mode, NULL);
+  set_optab_libfunc (ne_optab, mode, NULL);
+  set_optab_libfunc (lt_optab, mode, NULL);
+  set_optab_libfunc (le_optab, mode, NULL);
+  set_optab_libfunc (ge_optab, mode, NULL);
+  set_optab_libfunc (gt_optab, mode, NULL);
+  set_optab_libfunc (unord_optab, mode, NULL);
+}
+
+static void
+riscv_init_libfuncs (void)
+{
+  riscv_block_arith_comp_libfuncs_for_mode (HFmode);
+  riscv_block_arith_comp_libfuncs_for_mode (BFmode);
+
+  /* Convert between BFmode and HFmode using only trunc libfunc if needed.  */
+  set_conv_libfunc (sext_optab, BFmode, HFmode, "__trunchfbf2");
+  set_conv_libfunc (sext_optab, HFmode, BFmode, "__truncbfhf2");
+  set_conv_libfunc (trunc_optab, BFmode, HFmode, "__trunchfbf2");
+  set_conv_libfunc (trunc_optab, HFmode, BFmode, "__truncbfhf2");
 }
 
 #if CHECKING_P
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index d4676507b452..24558682eb8f 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -196,7 +196,7 @@
   (const_string "unknown"))
 
 ;; Main data type used by the insn
-(define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,HF,SF,DF,TF,
+(define_attr "mode" "unknown,none,QI,HI,SI,DI,TI,HF,BF,SF,DF,TF,
   RVVMF64BI,RVVMF32BI,RVVMF16BI,RVVMF8BI,RVVMF4BI,RVVMF2BI,RVVM1BI,
   RVVM8QI,RVVM4QI,RVVM2QI,RVVM1QI,RVVMF2QI,RVVMF4QI,RVVMF8QI,
   RVVM8HI,RVVM4HI,RVVM2HI,RVVM1HI,RVVMF2HI,RVVMF4HI,
@@ -1887,12 +1887,12 @@
    (set_attr "mode" "DF")])
 
 ;; 16-bit floating point moves
-(define_expand "movhf"
-  [(set (match_operand:HF 0 "")
-	(match_operand:HF 1 ""))]
+(define_expand "mov<mode>"
+  [(set (match_operand:HFBF 0 "")
+	(match_operand:HFBF 1 ""))]
   ""
 {
-  if (riscv_legitimize_move (HFmode, operands[0], operands[1]))
+  if (riscv_legitimize_move (<MODE>mode, operands[0], operands[1]))
     DONE;
 })
 
@@ -1907,16 +1907,16 @@
    (set_attr "type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "HF")])
 
-(define_insn "*movhf_softfloat"
-  [(set (match_operand:HF 0 "nonimmediate_operand" "=f, r,r,m,*f,*r")
-	(match_operand:HF 1 "move_operand"         " f,Gr,m,r,*r,*f"))]
-  "!TARGET_ZFHMIN
-   && (register_operand (operands[0], HFmode)
-       || reg_or_0_operand (operands[1], HFmode))"
+(define_insn "*mov<mode>_softfloat"
+  [(set (match_operand:HFBF 0 "nonimmediate_operand" "=f, r,r,m,*f,*r")
+	(match_operand:HFBF 1 "move_operand"	     " f,Gr,m,r,*r,*f"))]
+  "((!TARGET_ZFHMIN && <MODE>mode == HFmode) || (<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,move,load,store,mtc,mfc")
    (set_attr "type" "fmove,move,load,store,mtc,mfc")
-   (set_attr "mode" "HF")])
+   (set_attr "mode" "<MODE>")])
 
 (define_insn "*movhf_softfloat_boxing"
   [(set (match_operand:HF 0 "register_operand"            "=f")
diff --git a/gcc/testsuite/gcc.target/riscv/bf16_arithmetic.c b/gcc/testsuite/gcc.target/riscv/bf16_arithmetic.c
new file mode 100644
index 000000000000..9e4850512600
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bf16_arithmetic.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i -mabi=ilp32 -O" { target { rv32 } } } */
+/* { dg-options "-march=rv64i -mabi=lp64 -O" { target { rv64 } } } */
+
+/* 1) bf -> sf          (call      __extendbfsf2)  */
+/* 2) sf1 [+|-|*|/] sf2 (call      __[add|sub|mul|div]sf3)  */
+/* 3) sf -> bf          (call      __truncsfbf2)  */
+extern _Bfloat16 bf;
+extern _Bfloat16 bf1;
+extern _Bfloat16 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 "call\t__extendbfsf2" 16 } } */
+/* { dg-final { scan-assembler-times "call\t__truncsfbf2" 10 } } */
+/* { dg-final { scan-assembler-times "call\t__addsf3" 3 } } */
+/* { dg-final { scan-assembler-times "call\t__subsf3" 3 } } */
+/* { dg-final { scan-assembler-times "call\t__mulsf3" 2 } } */
+/* { dg-final { scan-assembler-times "call\t__divsf3" 2 } } */
+
+/* { dg-final { scan-assembler-not "call\t__addbf3" } } */
+/* { dg-final { scan-assembler-not "call\t__subbf3" } } */
+/* { dg-final { scan-assembler-not "call\t__mulbf3" } } */
+/* { dg-final { scan-assembler-not "call\t__divbf3" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/bf16_call.c b/gcc/testsuite/gcc.target/riscv/bf16_call.c
new file mode 100644
index 000000000000..29f677199997
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bf16_call.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i -mabi=ilp32 -O" { target { rv32 } } } */
+/* { dg-options "-march=rv64i -mabi=lp64 -O" { target { rv64 } } } */
+
+/* 1) bf -> sf (call      __extendbfsf2)  */
+/* 2) sf -> bf (call      __truncsfbf2)  */
+__attribute__ ((noinline)) _Bfloat16 add (_Bfloat16 a, _Bfloat16 b) { return a + b; }
+
+_Bfloat16 test(_Bfloat16 a, _Bfloat16 b) { return add (a, b); }
+
+/* { dg-final { scan-assembler-times "call\t__extendbfsf2" 2 } } */
+/* { dg-final { scan-assembler-times "call\t__truncsfbf2" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/bf16_comparison.c b/gcc/testsuite/gcc.target/riscv/bf16_comparison.c
new file mode 100644
index 000000000000..69db803f403e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bf16_comparison.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i -mabi=ilp32 -O" { target { rv32 } } } */
+/* { dg-options "-march=rv64i -mabi=lp64 -O" { target { rv64 } } } */
+
+/* 1) bf -> sf               (call	__extendbfsf2)  */
+/* 2) sf1 [<|<=|>|>=|==] sf2 (call	__[lt|le|gt|ge|eq]sf2)  */
+extern _Bfloat16 bf;
+extern _Bfloat16 bf1;
+extern _Bfloat16 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 "call\t__extendbfsf2" 15 } } */
+/* { dg-final { scan-assembler-not "call\t__ltbf2" } } */
+/* { dg-final { scan-assembler-not "call\t__lebf2" } } */
+/* { dg-final { scan-assembler-not "call\t__gtbf2" } } */
+/* { dg-final { scan-assembler-not "call\t__gebf2" } } */
+/* { dg-final { scan-assembler-not "call\t__eqbf2" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/bf16_float_libcall_convert.c b/gcc/testsuite/gcc.target/riscv/bf16_float_libcall_convert.c
new file mode 100644
index 000000000000..ba6c6460bc2c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bf16_float_libcall_convert.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i -mabi=ilp32 -O" { target { rv32 } } } */
+/* { dg-options "-march=rv64i -mabi=lp64 -O" { target { rv64 } } } */
+
+
+/* 1) float       -> BF16
+ *    hf/sf/df/tf -> bf                   (call   __trunc[h|s|d|t]fbf2)
+*/
+
+/* 2) BF16        -> float
+ *    bf          -> hf == sf -> hf       (call   __truncsfhf2)
+ *    bf          -> sf                   (call   __extendbfsf2)
+ *    bf          -> df == bf -> sf -> df (call   __extendbfsf2 && __extendsfdf2)
+ *    bf          -> tf == bf -> sf -> tf (call   __extendbfsf2 && __extendsftf2)
+*/
+
+extern   _Bfloat16 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 "call\t__extendbfsf2" 3 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__extendbfsf2" 3 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__extendsfdf2" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__extendsfdf2" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__extendsftf2" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__extendsftf2" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__truncsfhf2" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__truncsfhf2" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__trunchfbf2" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__trunchfbf2" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__truncsfbf2" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__truncsfbf2" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__truncdfbf2" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__truncdfbf2" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__trunctfbf2" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__trunctfbf2" 1 { target { rv64 } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/bf16_integer_libcall_convert.c b/gcc/testsuite/gcc.target/riscv/bf16_integer_libcall_convert.c
new file mode 100644
index 000000000000..ad714253a4a5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bf16_integer_libcall_convert.c
@@ -0,0 +1,81 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32i -mabi=ilp32 -O" { target { rv32 } } } */
+/* { dg-options "-march=rv64i -mabi=lp64 -O" { target { rv64 } } } */
+
+/* 1) Integer     -> BF16 
+ *    qi/hi/si    -> bf (call	__floatsibf) 
+ *    uqi/uhi/usi -> bf (call	__floatunsibf)  
+ *    di/ti       -> bf (call	__float[d|t]ibf)
+ *    udi/uti     -> bf (call	__floatun[d|t]ibf)
+*/
+
+/* 2) BF16        -> Integer
+ *    bf          -> qi/hi/si    (call   __fixsfsi)
+ *    bf          -> uqi/uhi/usi (call   __fixunssfsi)
+ *    bf          -> di/ti       (call   __fixsf[d|t]i)
+ *    bf          -> udi/uti     (call   __fixunssf[d|t]i)
+*/
+
+extern _Bfloat16 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 "call\t__fixsfsi" 3 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__fixsfsi" 3 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__fixsfdi" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__fixsfdi" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__fixunssfsi" 3 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__fixunssfsi" 3 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__fixunssfdi" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__fixunssfdi" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__floatsibf" 3 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__floatsibf" 3 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__floatdibf" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__floatdibf" 1 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__floatunsibf" 3 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__floatunsibf" 3 { target { rv64 } } } } */
+
+/* { dg-final { scan-assembler-times "call\t__floatundibf" 1 { target { rv32 } } } } */
+/* { dg-final { scan-assembler-times "call\t__floatundibf" 1 { target { rv64 } } } } */
diff --git a/libgcc/config/riscv/sfp-machine.h b/libgcc/config/riscv/sfp-machine.h
index 0ad97081e884..9d3552ce48f6 100644
--- a/libgcc/config/riscv/sfp-machine.h
+++ b/libgcc/config/riscv/sfp-machine.h
@@ -41,6 +41,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_2_udiv(D,R,X,Y)
 #define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_4_udiv(Q,R,X,Y)
 
+#define _FP_NANFRAC_B		_FP_QNANBIT_B
 #define _FP_NANFRAC_H		_FP_QNANBIT_H
 #define _FP_NANFRAC_S		_FP_QNANBIT_S
 #define _FP_NANFRAC_D		_FP_QNANBIT_D, 0
@@ -64,6 +65,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define _FP_DIV_MEAT_D(R,X,Y)	_FP_DIV_MEAT_1_udiv_norm(D,R,X,Y)
 #define _FP_DIV_MEAT_Q(R,X,Y)	_FP_DIV_MEAT_2_udiv(Q,R,X,Y)
 
+#define _FP_NANFRAC_B		_FP_QNANBIT_B
 #define _FP_NANFRAC_H		_FP_QNANBIT_H
 #define _FP_NANFRAC_S		_FP_QNANBIT_S
 #define _FP_NANFRAC_D		_FP_QNANBIT_D
@@ -82,6 +84,7 @@ typedef unsigned int UTItype __attribute__ ((mode (TI)));
 typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__)));
 #define CMPtype __gcc_CMPtype
 
+#define _FP_NANSIGN_B		0
 #define _FP_NANSIGN_H		0
 #define _FP_NANSIGN_S		0
 #define _FP_NANSIGN_D		0
diff --git a/libgcc/config/riscv/t-softfp32 b/libgcc/config/riscv/t-softfp32
index 1a3b1caa6b06..da55eb348c18 100644
--- a/libgcc/config/riscv/t-softfp32
+++ b/libgcc/config/riscv/t-softfp32
@@ -42,7 +42,11 @@ softfp_extras += divsf3 divdf3 divtf3
 
 endif
 
-softfp_extensions += hfsf hfdf hftf
-softfp_truncations += tfhf dfhf sfhf
+softfp_extensions += hfsf hfdf hftf \
+		     bfsf
+softfp_truncations += tfhf dfhf sfhf \
+		      tfbf dfbf sfbf \
+		      hfbf bfhf
 softfp_extras += fixhfsi fixhfdi fixunshfsi fixunshfdi \
-                 floatsihf floatdihf floatunsihf floatundihf
+		 floatsihf floatdihf floatunsihf floatundihf \
+		 floatsibf floatdibf floatunsibf floatundibf
diff --git a/libgcc/config/riscv/t-softfp64 b/libgcc/config/riscv/t-softfp64
index c87d242d5c3a..936e58e6cb19 100644
--- a/libgcc/config/riscv/t-softfp64
+++ b/libgcc/config/riscv/t-softfp64
@@ -1,4 +1,5 @@
 include $(srcdir)/config/riscv/t-softfp32
 
 softfp_int_modes += ti
-softfp_extras += fixhfti fixunshfti floattihf floatuntihf
+softfp_extras += fixhfti fixunshfti floattihf floatuntihf \
+		 floattibf floatuntibf
diff --git a/libgcc/soft-fp/floatsibf.c b/libgcc/soft-fp/floatsibf.c
new file mode 100644
index 000000000000..0cb05e58fc18
--- /dev/null
+++ b/libgcc/soft-fp/floatsibf.c
@@ -0,0 +1,45 @@
+/* Software floating-point emulation.
+   Convert a 32bit signed integer to bfloat16
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "soft-fp.h"
+#include "brain.h"
+
+BFtype
+__floatsibf (SItype i)
+{
+  FP_DECL_EX;
+  FP_DECL_B (A);
+  BFtype a;
+
+  FP_INIT_ROUNDMODE;
+  FP_FROM_INT_B (A, i, SI_BITS, USItype);
+  FP_PACK_RAW_B (a, A);
+  FP_HANDLE_EXCEPTIONS;
+
+  return a;
+}
diff --git a/libgcc/soft-fp/floatunsibf.c b/libgcc/soft-fp/floatunsibf.c
new file mode 100644
index 000000000000..cd8c4bc88397
--- /dev/null
+++ b/libgcc/soft-fp/floatunsibf.c
@@ -0,0 +1,45 @@
+/* Software floating-point emulation.
+   Convert a 32bit unsigned integer to bfloat16
+   Copyright (C) 2007-2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "soft-fp.h"
+#include "brain.h"
+
+BFtype
+__floatunsibf (USItype i)
+{
+  FP_DECL_EX;
+  FP_DECL_B (A);
+  BFtype a;
+
+  FP_INIT_ROUNDMODE;
+  FP_FROM_INT_B (A, i, SI_BITS, USItype);
+  FP_PACK_RAW_B (a, A);
+  FP_HANDLE_EXCEPTIONS;
+
+  return a;
+}


More information about the Gcc-cvs mailing list