From patchwork Tue Apr 2 09:22:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiao Zeng X-Patchwork-Id: 1918706 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4V82P92pXKz1yYw for ; Tue, 2 Apr 2024 20:18:37 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id AB770385DC3F for ; Tue, 2 Apr 2024 09:18:35 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from sgoci-sdnproxy-2.icoremail.net (sgoci-sdnproxy-2.icoremail.net [168.138.187.110]) by sourceware.org (Postfix) with ESMTP id C29F43858C36 for ; Tue, 2 Apr 2024 09:17:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C29F43858C36 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=eswincomputing.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=eswincomputing.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C29F43858C36 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=168.138.187.110 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712049483; cv=none; b=eJ9/NqmOv8nSNYgKfxQtexvHz8jKQ8E89p23egUfCF5UWk/r3kxUPUp87MCfLd7OzdCK8vAIHDEdX2CTPs7e7vX5pONjTntAFbtOrdQQNdSmQ1ERNOo912KNhneAbwSFIwveCXJd0R3hMVe5jFTdXqc4o50zZfqDTLm7PezLFGo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712049483; c=relaxed/simple; bh=BynrVAa90vE/eqOdysumfGSEjMW3h+yreurqPQUTDZA=; h=From:To:Subject:Date:Message-Id; b=ASus/Zn/uja4q0WBuuhf2xsMNeJqe4wKqwrfRUzBzC9a9dOMtZctBYUjXllBd1ceHf+eRWahhGz1LgRbXv0J3mFv1gJSLplLAjAv4Kf+wUC/usdntQnDfvxw2auWuAtv7lblbyS67HUyP8Po/1kNqfKEHdJCb6bAg3H9WsCpqI0= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from localhost.localdomain (unknown [10.12.130.38]) by app2 (Coremail) with SMTP id TQJkCgAHGbv9zAtmP3kEAA--.14582S5; Tue, 02 Apr 2024 17:16:50 +0800 (CST) From: Xiao Zeng To: gcc-patches@gcc.gnu.org Cc: jeffreyalaw@gmail.com, research_trasio@irq.a4lg.com, kito.cheng@gmail.com, zhengyu@eswincomputing.com, jinma@linux.alibaba.com, Xiao Zeng Subject: [PATCH v2 1/1] [RISC-V] Add support for _Bfloat16 Date: Tue, 2 Apr 2024 17:22:10 +0800 Message-Id: <20240402092210.80779-2-zengxiao@eswincomputing.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20240402092210.80779-1-zengxiao@eswincomputing.com> References: <20240402092210.80779-1-zengxiao@eswincomputing.com> X-CM-TRANSID: TQJkCgAHGbv9zAtmP3kEAA--.14582S5 X-Coremail-Antispam: 1UD129KBjvAXoWfAw48tr1xXFW3Aw1DKFWfKrg_yoW5Wr13Wo Z5trs5X345Zr1S9FZa9w47Xr4DZ3W8CrsxXanayFyrCF1DX3WrA3yUtw4fZwn8JFyfXFyU ZayrJa93AayUKr4rn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYA7AC8VAFwI0_Xr0_Wr1l1xkIjI8I6I8E6xAIw20EY4v20xva j40_Wr0E3s1l1IIY67AEw4v_Jr0_Jr4l82xGYIkIc2x26280x7IE14v26r18M28IrcIa0x kI8VCY1x0267AKxVWUCVW8JwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK021l84AC jcxK6xIIjxv20xvE14v26w1j6s0DM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r4UJVWxJr 1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_GcCE3s1l e2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI 8IcVAFwI0_Jr0_Jr4lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJVW8JwAC jcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lc2xSY4AK6svPMxAIw28Icx kI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2Iq xVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUAVWUtwCIc40Y0x0EwIxGrwCI42 IY6xIIjxv20xvE14v26r1j6r1xMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY 6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aV CY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7VUbec_DUUUUU== X-CM-SenderInfo: p2hqw5xldrqvxvzl0uprps33xlqjhudrp/ X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_NUMSUBJECT, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org 1 At point , BF16 has already been completed "post public review". 2 LLVM has also added support for RISCV BF16 in and . 3 According to the discussion , 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): Ditto. (*movhf_softfloat): Ditto. (*mov_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 --- 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.target/riscv/bf16_arithmetic.c | 42 ++++++++++ gcc/testsuite/gcc.target/riscv/bf16_call.c | 12 +++ .../gcc.target/riscv/bf16_comparison.c | 36 +++++++++ .../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(-) create mode 100644 gcc/testsuite/gcc.target/riscv/bf16_arithmetic.c create mode 100644 gcc/testsuite/gcc.target/riscv/bf16_call.c create mode 100644 gcc/testsuite/gcc.target/riscv/bf16_comparison.c create mode 100644 gcc/testsuite/gcc.target/riscv/bf16_float_libcall_convert.c create mode 100644 gcc/testsuite/gcc.target/riscv/bf16_integer_libcall_convert.c create mode 100644 libgcc/soft-fp/floatsibf.c create mode 100644 libgcc/soft-fp/floatunsibf.c diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md index a7694137685..40bf20f42bb 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 d457e306dd1..4c08834288a 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 bdce89b17aa..6de4e440298 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 fe9976bfffe..0cd3dd8a23d 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -9873,9 +9873,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 @@ -9896,19 +9904,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); @@ -9959,27 +9968,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 0346cc3859d..3d266ad5c41 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -197,7 +197,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, @@ -1921,12 +1921,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" + [(set (match_operand:HFBF 0 "") + (match_operand:HFBF 1 ""))] "" { - if (riscv_legitimize_move (HFmode, operands[0], operands[1])) + if (riscv_legitimize_move (mode, operands[0], operands[1])) DONE; }) @@ -1941,16 +1941,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_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 == HFmode) || (mode == BFmode)) + && (register_operand (operands[0], mode) + || reg_or_0_operand (operands[1], 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" "")]) (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 00000000000..9e485051260 --- /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 00000000000..29f67719999 --- /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 00000000000..69db803f403 --- /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 00000000000..ba6c6460bc2 --- /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 00000000000..ad714253a4a --- /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 0ad97081e88..9d3552ce48f 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 1a3b1caa6b0..5e2442fb586 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 c87d242d5c3..6078bed439a 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 00000000000..0cb05e58fc1 --- /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 + . */ + +#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 00000000000..cd8c4bc8839 --- /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 + . */ + +#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; +}