[v3] LoongArch:Implement 128-bit floating point functions in gcc.
Checks
Commit Message
In the implementation process, the "q" suffix function is
Re-register and associate the "__float128" type with the
"long double" type so that the compiler can handle the
corresponding function correctly. The functions implemented
include __builtin_{huge_valq infq, fabsq, copysignq, nanq,nansq}.
On the LoongArch architecture, __builtin_{fabsq,copysignq} can
be implemented with the instruction "bstrins.d", so that its
optimization effect reaches the optimal value.
gcc/ChangeLog:
* config/loongarch/loongarch-builtins.cc (DEF_LARCH_FTYPE):
(enum loongarch_builtin_type):Increases the type of the function.
(FLOAT_BUILTIN_HIQ):__builtin_{huge_valq,infq}.
(FLOAT_BUILTIN_FCQ):__builtin_{fabsq,copysignq}.
(FLOAT_BUILTIN_NNQ):__builtin_{nanq,nansq}.
(loongarch_init_builtins):
(loongarch_fold_builtin):
(loongarch_expand_builtin):
* config/loongarch/loongarch-protos.h (loongarch_fold_builtin):
(loongarch_c_mode_for_suffix):Add the declaration of the function.
* config/loongarch/loongarch.cc (loongarch_c_mode_for_suffix):Add
the definition of the function.
(TARGET_FOLD_BUILTIN):
(TARGET_C_MODE_FOR_SUFFIX):
* config/loongarch/loongarch.md (infq):Add an instruction template
to the machine description file to generate information such as
the icode used by the function and the constructor.
(<mathq_pattern>):
(fabsq):
(copysignq):
libgcc/ChangeLog:
* config/loongarch/t-softfp-tf:
* config/loongarch/tf-signs.c: New file.
---
gcc/config/loongarch/loongarch-builtins.cc | 168 ++++++++++++++++++++-
gcc/config/loongarch/loongarch-protos.h | 2 +
gcc/config/loongarch/loongarch.cc | 14 ++
gcc/config/loongarch/loongarch.md | 69 +++++++++
libgcc/config/loongarch/t-softfp-tf | 3 +
libgcc/config/loongarch/tf-signs.c | 59 ++++++++
6 files changed, 313 insertions(+), 2 deletions(-)
create mode 100644 libgcc/config/loongarch/tf-signs.c
Comments
Please fix code style (this is the third time I say it and I'm really
frustrated now). GCC is a project, it's not a student homework so style
matters. And it's not so difficult to fix the style: for a new file you
can use "clang-format --style GNU -i filename.c" to do the work
automatically.
On Tue, 2023-08-15 at 18:39 +0800, chenxiaolong wrote:
> In the implementation process, the "q" suffix function is
> Re-register and associate the "__float128" type with the
> "long double" type so that the compiler can handle the
> corresponding function correctly. The functions implemented
> include __builtin_{huge_valq infq, fabsq, copysignq, nanq,nansq}.
> On the LoongArch architecture, __builtin_{fabsq,copysignq} can
> be implemented with the instruction "bstrins.d", so that its
> optimization effect reaches the optimal value.
>
> gcc/ChangeLog:
>
> * config/loongarch/loongarch-builtins.cc (DEF_LARCH_FTYPE):
> (enum loongarch_builtin_type):Increases the type of the function.
> (FLOAT_BUILTIN_HIQ):__builtin_{huge_valq,infq}.
> (FLOAT_BUILTIN_FCQ):__builtin_{fabsq,copysignq}.
> (FLOAT_BUILTIN_NNQ):__builtin_{nanq,nansq}.
> (loongarch_init_builtins):
> (loongarch_fold_builtin):
> (loongarch_expand_builtin):
> * config/loongarch/loongarch-protos.h (loongarch_fold_builtin):
> (loongarch_c_mode_for_suffix):Add the declaration of the function.
> * config/loongarch/loongarch.cc (loongarch_c_mode_for_suffix):Add
> the definition of the function.
> (TARGET_FOLD_BUILTIN):
> (TARGET_C_MODE_FOR_SUFFIX):
> * config/loongarch/loongarch.md (infq):Add an instruction template
> to the machine description file to generate information such as
> the icode used by the function and the constructor.
> (<mathq_pattern>):
> (fabsq):
> (copysignq):
>
> libgcc/ChangeLog:
>
> * config/loongarch/t-softfp-tf:
> * config/loongarch/tf-signs.c: New file.
> ---
> gcc/config/loongarch/loongarch-builtins.cc | 168 ++++++++++++++++++++-
> gcc/config/loongarch/loongarch-protos.h | 2 +
> gcc/config/loongarch/loongarch.cc | 14 ++
> gcc/config/loongarch/loongarch.md | 69 +++++++++
> libgcc/config/loongarch/t-softfp-tf | 3 +
> libgcc/config/loongarch/tf-signs.c | 59 ++++++++
> 6 files changed, 313 insertions(+), 2 deletions(-)
> create mode 100644 libgcc/config/loongarch/tf-signs.c
>
> diff --git a/gcc/config/loongarch/loongarch-builtins.cc b/gcc/config/loongarch/loongarch-builtins.cc
> index b929f224dfa..2fb0fde0e3f 100644
> --- a/gcc/config/loongarch/loongarch-builtins.cc
> +++ b/gcc/config/loongarch/loongarch-builtins.cc
> @@ -36,6 +36,8 @@ along with GCC; see the file COPYING3. If not see
> #include "fold-const.h"
> #include "expr.h"
> #include "langhooks.h"
> +#include "calls.h"
> +#include "explow.h"
>
> /* Macros to create an enumeration identifier for a function prototype. */
> #define LARCH_FTYPE_NAME1(A, B) LARCH_##A##_FTYPE_##B
> @@ -48,9 +50,18 @@ enum loongarch_function_type
> #define DEF_LARCH_FTYPE(NARGS, LIST) LARCH_FTYPE_NAME##NARGS LIST,
> #include "config/loongarch/loongarch-ftypes.def"
> #undef DEF_LARCH_FTYPE
> + LARCH_BUILTIN_HUGE_VALQ,
> + LARCH_BUILTIN_INFQ,
> + LARCH_BUILTIN_FABSQ,
> + LARCH_BUILTIN_COPYSIGNQ,
> + LARCH_BUILTIN_NANQ,
> + LARCH_BUILTIN_NANSQ,
> LARCH_MAX_FTYPE_MAX
> };
>
> +/* Count the number of functions with "q" as the suffix. */
> +const int MATHQ_NUMS = (int)LARCH_MAX_FTYPE_MAX - (int)LARCH_BUILTIN_HUGE_VALQ;
> +
> /* Specifies how a built-in function should be converted into rtl. */
> enum loongarch_builtin_type
> {
> @@ -63,6 +74,15 @@ enum loongarch_builtin_type
> value and the arguments are mapped to operands 0 and above. */
> LARCH_BUILTIN_DIRECT_NO_TARGET,
>
> + /* The function corresponds to __builtin_{huge_valq,infq}. */
> + LARCH_BUILTIN_HIQ_DIRECT,
> +
> + /* The function corresponds to __builtin_{fabsq,copysignq}. */
> + LARCH_BUILTIN_FCQ_DIRECT,
> +
> + /* Define the type of the __builtin_{nanq,nansq} function. */
> + LARCH_BUILTIN_NNQ_DIRECT
> +
> };
>
> /* Declare an availability predicate for built-in functions that require
> @@ -136,6 +156,24 @@ AVAIL_ALL (hard_float, TARGET_HARD_FLOAT_ABI)
> LARCH_BUILTIN (INSN, #INSN, LARCH_BUILTIN_DIRECT_NO_TARGET, \
> FUNCTION_TYPE, AVAIL)
>
> +/* Define an float to do funciton {huge_valq,infq}. */
> +#define FLOAT_BUILTIN_HIQ (INSN, FUNCTION_TYPE) \
> + { CODE_FOR_ ## INSN, \
> + "__builtin_" #INSN, LARCH_BUILTIN_HIQ_DIRECT, \
> + FUNCTION_TYPE, loongarch_builtin_avail_default }
> +
> +/* Define an float to do funciton {fabsq,copysignq}. */
> +#define FLOAT_BUILTIN_FCQ (INSN, FUNCTION_TYPE) \
> + { CODE_FOR_ ## INSN, \
> + "__builtin_" #INSN, LARCH_BUILTIN_FCQ_DIRECT, \
> + FUNCTION_TYPE, loongarch_builtin_avail_default }
> +
> +/* Define an float to do funciton {nanq,nansq}. */
> +#define FLOAT_BUILTIN_NNQ (INSN, FUNCTION_TYPE) \
> + { CODE_FOR_ ## INSN, \
> + "__builtin_" #INSN, LARCH_BUILTIN_NNQ_DIRECT, \
> + FUNCTION_TYPE, loongarch_builtin_avail_default }
> +
> static const struct loongarch_builtin_description loongarch_builtins[] = {
> #define LARCH_MOVFCSR2GR 0
> DIRECT_BUILTIN (movfcsr2gr, LARCH_USI_FTYPE_UQI, hard_float),
> @@ -183,6 +221,14 @@ static const struct loongarch_builtin_description loongarch_builtins[] = {
> DIRECT_NO_TARGET_BUILTIN (asrtgt_d, LARCH_VOID_FTYPE_DI_DI, default),
> DIRECT_NO_TARGET_BUILTIN (syscall, LARCH_VOID_FTYPE_USI, default),
> DIRECT_NO_TARGET_BUILTIN (break, LARCH_VOID_FTYPE_USI, default),
> +
> + FLOAT_BUILTIN_HIQ (huge_valq, LARCH_BUILTIN_HUGE_VALQ),
> + FLOAT_BUILTIN_HIQ (infq, LARCH_BUILTIN_INFQ),
> + FLOAT_BUILTIN_FCQ (fabsq, LARCH_BUILTIN_FABSQ),
> + FLOAT_BUILTIN_FCQ (copysignq, LARCH_BUILTIN_COPYSIGNQ),
> + FLOAT_BUILTIN_NNQ (nanq, LARCH_BUILTIN_NANQ),
> + FLOAT_BUILTIN_NNQ (nansq, LARCH_BUILTIN_NANSQ),
> +
> };
>
> /* Index I is the function declaration for loongarch_builtins[I], or null if
> @@ -255,10 +301,13 @@ loongarch_init_builtins (void)
> const struct loongarch_builtin_description *d;
> unsigned int i;
> tree type;
> + tree const_string_type
> + =build_pointer_type (build_qualified_type (char_type_node,
> + TYPE_QUAL_CONST));
>
> /* Iterate through all of the bdesc arrays, initializing all of the
> builtin functions. */
> - for (i = 0; i < ARRAY_SIZE (loongarch_builtins); i++)
> + for (i = 0; i < ARRAY_SIZE (loongarch_builtins)-MATHQ_NUMS; i++)
> {
> d = &loongarch_builtins[i];
> if (d->avail ())
> @@ -270,6 +319,63 @@ loongarch_init_builtins (void)
> loongarch_get_builtin_decl_index[d->icode] = i;
> }
> }
> + /* Register the type long_double_type_node as a built-in type and
> + give it an alias "__float128". */
> + (*lang_hooks.types.register_builtin_type) (long_double_type_node,
> + "__float128");
> +
> + type = build_function_type_list (long_double_type_node, NULL_TREE);
> + d = &loongarch_builtins[i];
> + loongarch_builtin_decls[i]
> + =add_builtin_function ("__builtin_huge_valq", type,
> + i, BUILT_IN_MD, NULL, NULL_TREE);
> + loongarch_get_builtin_decl_index[d->icode]=i++;
> +
> + type = build_function_type_list (long_double_type_node, NULL_TREE);
> + d = &loongarch_builtins[i];
> + loongarch_builtin_decls[i]
> + =add_builtin_function ("__builtin_infq", type,
> + i, BUILT_IN_MD, NULL, NULL_TREE);
> + loongarch_get_builtin_decl_index[d->icode]=i++;
> +
> + type = build_function_type_list (long_double_type_node,
> + long_double_type_node,
> + NULL_TREE);
> + d = &loongarch_builtins[i];
> + loongarch_builtin_decls[i]
> + =add_builtin_function ("__builtin_fabsq", type,
> + i, BUILT_IN_MD, NULL, NULL_TREE);
> + TREE_READONLY (loongarch_builtin_decls[i]) =1;
> + loongarch_get_builtin_decl_index[d->icode]=i++;
> +
> + type = build_function_type_list (long_double_type_node,
> + long_double_type_node,
> + long_double_type_node,
> + NULL_TREE);
> + d = &loongarch_builtins[i];
> + loongarch_builtin_decls[i]
> + =add_builtin_function ("__builtin_copysignq", type,
> + i, BUILT_IN_MD, NULL, NULL_TREE);
> + TREE_READONLY (loongarch_builtin_decls[i]) =1;
> + loongarch_get_builtin_decl_index[d->icode]=i++;
> +
> + type=build_function_type_list (long_double_type_node,
> + const_string_type,
> + NULL_TREE);
> + d = &loongarch_builtins[i];
> + loongarch_builtin_decls[i]
> + =add_builtin_function ("__builtin_nanq", type,
> + i, BUILT_IN_MD, "__nanq", NULL_TREE);
> + TREE_READONLY (loongarch_builtin_decls[i]) =1;
> + loongarch_get_builtin_decl_index[d->icode]=i++;
> +
> + d = &loongarch_builtins[i];
> + loongarch_builtin_decls[i]
> + =add_builtin_function ("__builtin_nansq", type,
> + i, BUILT_IN_MD, "__nansq", NULL_TREE);
> + TREE_READONLY (loongarch_builtin_decls[i]) =1;
> + loongarch_get_builtin_decl_index[d->icode]=i;
> +
> }
>
> /* Implement TARGET_BUILTIN_DECL. */
> @@ -282,6 +388,42 @@ loongarch_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED)
> return loongarch_builtin_decls[code];
> }
>
> +tree
> +loongarch_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
> + tree *args, bool ignore ATTRIBUTE_UNUSED)
> +{
> + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
> + {
> + enum loongarch_function_type fn_code
> + = (enum loongarch_function_type) DECL_MD_FUNCTION_CODE (fndecl);
> + switch (fn_code)
> + {
> + case LARCH_BUILTIN_NANQ:
> + case LARCH_BUILTIN_NANSQ:
> + {
> + tree type = TREE_TYPE (TREE_TYPE (fndecl));
> + const char *str = c_getstr (*args);
> + int quiet = fn_code == LARCH_BUILTIN_NANQ;
> + REAL_VALUE_TYPE real;
> +
> + if (str && real_nan (&real, str, quiet, TYPE_MODE (type)))
> + return build_real (type, real);
> + return NULL_TREE;
> + }
> +
> + default:
> + break;
> + }
> + }
> +
> +#ifdef SUBTARGET_FOLD_BUILTIN
> + return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore);
> +#endif
> +
> + return NULL_TREE;
> +}
> +
> +
> /* Take argument ARGNO from EXP's argument list and convert it into
> an expand operand. Store the operand in *OP. */
>
> @@ -362,11 +504,33 @@ loongarch_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
> switch (d->builtin_type)
> {
> case LARCH_BUILTIN_DIRECT:
> + case LARCH_BUILTIN_FCQ_DIRECT:
> return loongarch_expand_builtin_direct (d->icode, target, exp, true);
>
> case LARCH_BUILTIN_DIRECT_NO_TARGET:
> return loongarch_expand_builtin_direct (d->icode, target, exp, false);
> - }
> +
> + case LARCH_BUILTIN_NNQ_DIRECT:
> + return expand_call ( exp ,target , ignore);
> +
> + case LARCH_BUILTIN_HIQ_DIRECT:
> + {
> + machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
> + REAL_VALUE_TYPE inf;
> + rtx tmp;
> +
> + real_inf (&inf);
> + tmp = const_double_from_real_value (inf, target_mode);
> +
> + tmp=validize_mem (force_const_mem (target_mode,tmp));
> +
> + if (target ==0)
> + target =gen_reg_rtx (target_mode);
> + emit_move_insn (target,tmp);
> +
> + return target;
> + }
> + }
> gcc_unreachable ();
> }
>
> diff --git a/gcc/config/loongarch/loongarch-protos.h b/gcc/config/loongarch/loongarch-protos.h
> index b71b188507a..35fc2ad7def 100644
> --- a/gcc/config/loongarch/loongarch-protos.h
> +++ b/gcc/config/loongarch/loongarch-protos.h
> @@ -175,11 +175,13 @@ extern void loongarch_register_frame_header_opt (void);
> /* Routines implemented in loongarch-c.c. */
> void loongarch_cpu_cpp_builtins (cpp_reader *);
>
> +extern tree loongarch_fold_builtin (tree, int, tree*, bool);
> extern void loongarch_init_builtins (void);
> extern void loongarch_atomic_assign_expand_fenv (tree *, tree *, tree *);
> extern tree loongarch_builtin_decl (unsigned int, bool);
> extern rtx loongarch_expand_builtin (tree, rtx, rtx subtarget ATTRIBUTE_UNUSED,
> machine_mode, int);
> extern tree loongarch_build_builtin_va_list (void);
> +extern machine_mode loongarch_c_mode_for_suffix (char suffix);
>
> #endif /* ! GCC_LOONGARCH_PROTOS_H */
> diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
> index 86d58784113..7a8358c9630 100644
> --- a/gcc/config/loongarch/loongarch.cc
> +++ b/gcc/config/loongarch/loongarch.cc
> @@ -6790,6 +6790,16 @@ loongarch_set_handled_components (sbitmap components)
> cfun->machine->reg_is_wrapped_separately[regno] = true;
> }
>
> +/* Target hook for c_mode_for_suffix. */
> +machine_mode
> +loongarch_c_mode_for_suffix (char suffix)
> +{
> + if (suffix == 'q')
> + return TFmode;
> +
> + return VOIDmode;
> +}
> +
> /* Initialize the GCC target structure. */
> #undef TARGET_ASM_ALIGNED_HI_OP
> #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
> @@ -6901,6 +6911,10 @@ loongarch_set_handled_components (sbitmap components)
> #define TARGET_BUILTIN_DECL loongarch_builtin_decl
> #undef TARGET_EXPAND_BUILTIN
> #define TARGET_EXPAND_BUILTIN loongarch_expand_builtin
> +#undef TARGET_FOLD_BUILTIN
> +#define TARGET_FOLD_BUILTIN loongarch_fold_builtin
> +#undef TARGET_C_MODE_FOR_SUFFIX
> +#define TARGET_C_MODE_FOR_SUFFIX loongarch_c_mode_for_suffix
>
> /* The generic ELF target does not always have TLS support. */
> #ifdef HAVE_AS_TLS
> diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md
> index b37e070660f..9fe3faf8b92 100644
> --- a/gcc/config/loongarch/loongarch.md
> +++ b/gcc/config/loongarch/loongarch.md
> @@ -44,6 +44,13 @@ (define_c_enum "unspec" [
> UNSPEC_FSCALEB
> UNSPEC_FLOGB
>
> + UNSPEC_INFQ
> + UNSPEC_HUGE_VALQ
> + UNSPEC_FABSQ
> + UNSPEC_COPYSIGNQ
> + UNSPEC_NANQ
> + UNSPEC_NANSQ
> +
> ;; Override return address for exception handling.
> UNSPEC_EH_RETURN
>
> @@ -563,6 +570,15 @@ (define_int_attr bytepick_imm [(8 "1")
> (48 "6")
> (56 "7")])
>
> +;; mathq function
> +(define_int_iterator MATHQ[UNSPEC_INFQ UNSPEC_HUGE_VALQ
> + UNSPEC_NANQ UNSPEC_NANSQ])
> +(define_int_attr mathq_pattern[(UNSPEC_INFQ "infq")
> + (UNSPEC_HUGE_VALQ "huge_valq")
> + (UNSPEC_NANQ "nanq")
> + (UNSPEC_NANSQ "nansq")]
> +)
> +
> ;;
> ;; ....................
> ;;
> @@ -2008,6 +2024,59 @@ (define_insn "movfcc"
> ""
> "movgr2cf\t%0,$r0")
>
> +;; Implements functions with a "q" suffix
> +
> +(define_insn "<mathq_pattern>"
> + [(unspec:SI[(const_int 0)] MATHQ)]
> + ""
> + "")
> +
> +;;Implement __builtin_fabsq function.
> +
> +(define_insn_and_split "fabsq"
> + [(set (match_operand:TF 0 "register_operand" "=r")
> + (unspec:TF[(match_operand:TF 1 "register_operand" "rG")]
> + UNSPEC_FABSQ))]
> + ""
> + "#"
> + "reload_completed"
> +[(set (zero_extract:DI (match_operand:DI 0 "register_operand")
> + (match_operand:SI 3 "const_int_operand")
> + (match_operand:SI 4 "const_int_operand"))
> + (match_operand:DI 2 "const_int_operand"))]
> +{
> + operands[0] = gen_rtx_REG (Pmode, REGNO (operands[0])+1);
> + operands[2] = GEN_INT (0);
> + operands[3] = GEN_INT (1);
> + operands[4] = GEN_INT (63);
> +}
> +)
> +
> +;;Implement __builtin_copysignq function.
> +
> +(define_insn_and_split "copysignq"
> + [(set (match_operand:TF 0 "register_operand" "=r")
> + (unspec:TF[(match_operand:TF 1 "register_operand" "rG")
> + (match_operand:TF 2 "register_operand" "rG")]
> + UNSPEC_COPYSIGNQ))]
> + ""
> + "#"
> + "reload_completed"
> + [(set (match_operand:DI 2 "register_operand")
> + (lshiftrt :DI (match_operand:DI 2 "register_operand")
> + (match_operand:SI 4 "arith_operand")))
> + (set (zero_extract:DI (match_operand:DI 0 "register_operand")
> + (match_operand:SI 3 "const_int_operand")
> + (match_operand:SI 4 "const_int_operand"))
> + (match_operand:DI 2 "register_operand"))]
> +{
> + operands[0] = gen_rtx_REG (Pmode,REGNO (operands[0])+1);
> + operands[2] = gen_rtx_REG (Pmode,REGNO (operands[2])+1);
> + operands[3] = GEN_INT (1);
> + operands[4] = GEN_INT (63);
> +}
> +)
> +
> ;; Conditional move instructions.
>
> (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
> diff --git a/libgcc/config/loongarch/t-softfp-tf b/libgcc/config/loongarch/t-softfp-tf
> index 306677b1255..0e7c2b4cabe 100644
> --- a/libgcc/config/loongarch/t-softfp-tf
> +++ b/libgcc/config/loongarch/t-softfp-tf
> @@ -1,3 +1,6 @@
> softfp_float_modes += tf
> softfp_extensions += sftf dftf
> softfp_truncations += tfsf tfdf
> +#Used to implement a special 128-bit function with a q suffix
> +LIB2ADD += $(srcdir)/config/loongarch/tf-signs.c
> +
> diff --git a/libgcc/config/loongarch/tf-signs.c b/libgcc/config/loongarch/tf-signs.c
> new file mode 100644
> index 00000000000..68db1729372
> --- /dev/null
> +++ b/libgcc/config/loongarch/tf-signs.c
> @@ -0,0 +1,59 @@
> +/* Copyright (C) 2008-2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC 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 General Public License
> +for more details.
> +
> +Under Section 7 of GPL version 3, you are granted additional
> +permissions described in the GCC Runtime Library Exception, version
> +3.1, as published by the Free Software Foundation.
> +
> +You should have received a copy of the GNU General Public License and
> +a copy of the GCC Runtime Library Exception along with this program;
> +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
> +<http://www.gnu.org/licenses/>. */
> +
> +union _FP_UNION_Q
> +{
> + __float128 flt;
> + struct
> + {
> + unsigned long frac0 : 64;
> + unsigned long frac1 : 48;
> + unsigned exp : 15;
> + unsigned sign : 1;
> + } bits __attribute__((packed));
> +};
> +
> +__float128 __nanq (const char *str);
> +__float128 __nansq (const char *str);
> +
> +__float128 __nanq (const char * str)
> +{
> + union _FP_UNION_Q nan;
> + nan.bits.frac0 = 0;
> + nan.bits.frac1 = 0;
> + nan.bits.exp = 0x7FFF;
> + nan.bits.sign = 0;
> +
> + return nan.flt;
> +}
> +__float128 __nansq (const char *str)
> +{
> + union _FP_UNION_Q nan;
> + nan.bits.frac0 = 0xFFFFFFFFFFFFFFFFUL;
> + nan.bits.frac1 = 0x0000FFFFFFFFFFFFUL;
> + nan.bits.exp = 0x7FFF;
> + nan.bits.sign = 0;
> +
> + return nan.flt;
> +}
> +
On Tue, 15 Aug 2023, chenxiaolong wrote:
> In the implementation process, the "q" suffix function is
> Re-register and associate the "__float128" type with the
> "long double" type so that the compiler can handle the
> corresponding function correctly. The functions implemented
> include __builtin_{huge_valq infq, fabsq, copysignq, nanq,nansq}.
> On the LoongArch architecture, __builtin_{fabsq,copysignq} can
> be implemented with the instruction "bstrins.d", so that its
> optimization effect reaches the optimal value.
Why? If long double has binary128 format, you shouldn't need any of these
functions at all; if it doesn't, just the C23 _Float128 type name and f128
constant suffix, and associated built-in functions defined in
builtins.def, should suffice (and since we now have _FloatN support for
C++, C++ no longer provides a reason for adding __float128 either).
__float128 is a legacy type name and feature and shouldn't be needed on
any new architectures, which can just use the standard type name from the
start.
Thanks for the tip! Similar functions (e.g. __builtin_fabsf128
(_Float128 a) are already supported by the compiler and can be handled
correctly, but functions that can be implemented on the LoongArch
architecture directly using the "bstrins" directive (e.g. fabsq,
copysignq, etc.) are better optimized because they generate fewer
assembly instructions. copysignq, etc.) on the LoongArch architecture
are better optimized because they generate fewer assembly instructions.
Translated with www.DeepL.com/Translator (free version)
在 2023-08-15二的 20:03 +0000,Joseph Myers写道:
> On Tue, 15 Aug 2023, chenxiaolong wrote:
>
> > In the implementation process, the "q" suffix function is
> > Re-register and associate the "__float128" type with the
> > "long double" type so that the compiler can handle the
> > corresponding function correctly. The functions implemented
> > include __builtin_{huge_valq infq, fabsq, copysignq,
> > nanq,nansq}.
> > On the LoongArch architecture, __builtin_{fabsq,copysignq}
> > can
> > be implemented with the instruction "bstrins.d", so that
> > its
> > optimization effect reaches the optimal value.
>
> Why? If long double has binary128 format, you shouldn't need any of
> these
> functions at all; if it doesn't, just the C23 _Float128 type name and
> f128
> constant suffix, and associated built-in functions defined in
> builtins.def, should suffice (and since we now have _FloatN support
> for
> C++, C++ no longer provides a reason for adding __float128 either).
> __float128 is a legacy type name and feature and shouldn't be needed
> on
> any new architectures, which can just use the standard type name from
> the
> start.
>
On Wed, 16 Aug 2023, chenxiaolong wrote:
> Thanks for the tip! Similar functions (e.g. __builtin_fabsf128
> (_Float128 a) are already supported by the compiler and can be handled
> correctly, but functions that can be implemented on the LoongArch
> architecture directly using the "bstrins" directive (e.g. fabsq,
> copysignq, etc.) are better optimized because they generate fewer
> assembly instructions. copysignq, etc.) on the LoongArch architecture
> are better optimized because they generate fewer assembly instructions.
Then you should make the existing built-in functions for _Float128 or long
double generate the desired instructions, rather than adding a legacy and
duplicative API to a new architecture.
On Tue, 2023-08-15 at 20:03 +0000, Joseph Myers wrote:
> On Tue, 15 Aug 2023, chenxiaolong wrote:
>
> > In the implementation process, the "q" suffix function is
> > Re-register and associate the "__float128" type with the
> > "long double" type so that the compiler can handle the
> > corresponding function correctly. The functions implemented
> > include __builtin_{huge_valq infq, fabsq, copysignq, nanq,nansq}.
> > On the LoongArch architecture, __builtin_{fabsq,copysignq} can
> > be implemented with the instruction "bstrins.d", so that its
> > optimization effect reaches the optimal value.
>
> Why? If long double has binary128 format, you shouldn't need any of these
> functions at all; if it doesn't, just the C23 _Float128 type name and f128
> constant suffix, and associated built-in functions defined in
> builtins.def, should suffice (and since we now have _FloatN support for
> C++, C++ no longer provides a reason for adding __float128 either).
> __float128 is a legacy type name and feature and shouldn't be needed on
> any new architectures, which can just use the standard type name from the
> start.
For _Float128 GCC already does the correct thing:
_Float128 g(_Float128 x) { return __builtin_fabsf128(x); }
compiled to (with -O2):
g:
.LFB3 = .
.cfi_startproc
bstrpick.d $r5,$r5,62,0
jr $r1
.cfi_endproc
So I guess we just need
builtin_define ("__builtin_fabsq=__builtin_fabsf128");
builtin_define ("__builtin_nanq=__builtin_nanf128");
etc. to map the "q" builtins to "f128" builtins if we really need the
"q" builtins.
Joseph: the problem here is many customers of LoongArch CPUs wish to
compile their old code with minimal change. Is it acceptable to add
these builtin_define's like rs6000-c.cc? Note "a new architecture" does
not mean we'll only compile post-C2x-era programs onto it.
Okay, thanks for the heads up! I'll try to format the code according to
the GNU Coding Standards. I'll double-check every line of the submitted
patch to make sure that I don't have such a low-level formatting
problem in every future patch, so that I can comply with the code
specification.
在 2023-08-15二的 18:48 +0800,Xi Ruoyao写道:
> Please fix code style (this is the third time I say it and I'm really
> frustrated now). GCC is a project, it's not a student homework so
> style
> matters. And it's not so difficult to fix the style: for a new file
> you
> can use "clang-format --style GNU -i filename.c" to do the work
> automatically.
>
> On Tue, 2023-08-15 at 18:39 +0800, chenxiaolong wrote:
> > In the implementation process, the "q" suffix function is
> > Re-register and associate the "__float128" type with the
> > "long double" type so that the compiler can handle the
> > corresponding function correctly. The functions implemented
> > include __builtin_{huge_valq infq, fabsq, copysignq,
> > nanq,nansq}.
> > On the LoongArch architecture, __builtin_{fabsq,copysignq}
> > can
> > be implemented with the instruction "bstrins.d", so that
> > its
> > optimization effect reaches the optimal value.
> >
> > gcc/ChangeLog:
> >
> > * config/loongarch/loongarch-builtins.cc (DEF_LARCH_FTYPE):
> > (enum loongarch_builtin_type):Increases the type of the
> > function.
> > (FLOAT_BUILTIN_HIQ):__builtin_{huge_valq,infq}.
> > (FLOAT_BUILTIN_FCQ):__builtin_{fabsq,copysignq}.
> > (FLOAT_BUILTIN_NNQ):__builtin_{nanq,nansq}.
> > (loongarch_init_builtins):
> > (loongarch_fold_builtin):
> > (loongarch_expand_builtin):
> > * config/loongarch/loongarch-protos.h
> > (loongarch_fold_builtin):
> > (loongarch_c_mode_for_suffix):Add the declaration of the
> > function.
> > * config/loongarch/loongarch.cc
> > (loongarch_c_mode_for_suffix):Add
> > the definition of the function.
> > (TARGET_FOLD_BUILTIN):
> > (TARGET_C_MODE_FOR_SUFFIX):
> > * config/loongarch/loongarch.md (infq):Add an instruction
> > template
> > to the machine description file to generate information
> > such as
> > the icode used by the function and the constructor.
> > (<mathq_pattern>):
> > (fabsq):
> > (copysignq):
> >
> > libgcc/ChangeLog:
> >
> > * config/loongarch/t-softfp-tf:
> > * config/loongarch/tf-signs.c: New file.
> > ---
> > gcc/config/loongarch/loongarch-builtins.cc | 168
> > ++++++++++++++++++++-
> > gcc/config/loongarch/loongarch-protos.h | 2 +
> > gcc/config/loongarch/loongarch.cc | 14 ++
> > gcc/config/loongarch/loongarch.md | 69 +++++++++
> > libgcc/config/loongarch/t-softfp-tf | 3 +
> > libgcc/config/loongarch/tf-signs.c | 59 ++++++++
> > 6 files changed, 313 insertions(+), 2 deletions(-)
> > create mode 100644 libgcc/config/loongarch/tf-signs.c
> >
> > diff --git a/gcc/config/loongarch/loongarch-builtins.cc
> > b/gcc/config/loongarch/loongarch-builtins.cc
> > index b929f224dfa..2fb0fde0e3f 100644
> > --- a/gcc/config/loongarch/loongarch-builtins.cc
> > +++ b/gcc/config/loongarch/loongarch-builtins.cc
> > @@ -36,6 +36,8 @@ along with GCC; see the file COPYING3. If not
> > see
> > #include "fold-const.h"
> > #include "expr.h"
> > #include "langhooks.h"
> > +#include "calls.h"
> > +#include "explow.h"
> >
> > /* Macros to create an enumeration identifier for a function
> > prototype. */
> > #define LARCH_FTYPE_NAME1(A, B) LARCH_##A##_FTYPE_##B
> > @@ -48,9 +50,18 @@ enum loongarch_function_type
> > #define DEF_LARCH_FTYPE(NARGS, LIST) LARCH_FTYPE_NAME##NARGS LIST,
> > #include "config/loongarch/loongarch-ftypes.def"
> > #undef DEF_LARCH_FTYPE
> > + LARCH_BUILTIN_HUGE_VALQ,
> > + LARCH_BUILTIN_INFQ,
> > + LARCH_BUILTIN_FABSQ,
> > + LARCH_BUILTIN_COPYSIGNQ,
> > + LARCH_BUILTIN_NANQ,
> > + LARCH_BUILTIN_NANSQ,
> > LARCH_MAX_FTYPE_MAX
> > };
> >
> > +/* Count the number of functions with "q" as the suffix. */
> > +const int MATHQ_NUMS = (int)LARCH_MAX_FTYPE_MAX -
> > (int)LARCH_BUILTIN_HUGE_VALQ;
> > +
> > /* Specifies how a built-in function should be converted into
> > rtl. */
> > enum loongarch_builtin_type
> > {
> > @@ -63,6 +74,15 @@ enum loongarch_builtin_type
> > value and the arguments are mapped to operands 0 and above.
> > */
> > LARCH_BUILTIN_DIRECT_NO_TARGET,
> >
> > + /* The function corresponds to __builtin_{huge_valq,infq}. */
> > + LARCH_BUILTIN_HIQ_DIRECT,
> > +
> > + /* The function corresponds to __builtin_{fabsq,copysignq}. */
> > + LARCH_BUILTIN_FCQ_DIRECT,
> > +
> > + /* Define the type of the __builtin_{nanq,nansq} function. */
> > + LARCH_BUILTIN_NNQ_DIRECT
> > +
> > };
> >
> > /* Declare an availability predicate for built-in functions that
> > require
> > @@ -136,6 +156,24 @@ AVAIL_ALL (hard_float, TARGET_HARD_FLOAT_ABI)
> > LARCH_BUILTIN (INSN, #INSN, LARCH_BUILTIN_DIRECT_NO_TARGET, \
> > FUNCTION_TYPE, AVAIL)
> >
> > +/* Define an float to do funciton {huge_valq,infq}. */
> > +#define FLOAT_BUILTIN_HIQ (INSN, FUNCTION_TYPE) \
> > + { CODE_FOR_ ## INSN, \
> > + "__builtin_" #INSN, LARCH_BUILTIN_HIQ_DIRECT, \
> > + FUNCTION_TYPE, loongarch_builtin_avail_default }
> > +
> > +/* Define an float to do funciton {fabsq,copysignq}. */
> > +#define FLOAT_BUILTIN_FCQ (INSN, FUNCTION_TYPE) \
> > + { CODE_FOR_ ## INSN, \
> > + "__builtin_" #INSN, LARCH_BUILTIN_FCQ_DIRECT, \
> > + FUNCTION_TYPE, loongarch_builtin_avail_default }
> > +
> > +/* Define an float to do funciton {nanq,nansq}. */
> > +#define FLOAT_BUILTIN_NNQ (INSN, FUNCTION_TYPE) \
> > + { CODE_FOR_ ## INSN, \
> > + "__builtin_" #INSN, LARCH_BUILTIN_NNQ_DIRECT, \
> > + FUNCTION_TYPE, loongarch_builtin_avail_default }
> > +
> > static const struct loongarch_builtin_description
> > loongarch_builtins[] = {
> > #define LARCH_MOVFCSR2GR 0
> > DIRECT_BUILTIN (movfcsr2gr, LARCH_USI_FTYPE_UQI, hard_float),
> > @@ -183,6 +221,14 @@ static const struct
> > loongarch_builtin_description loongarch_builtins[] = {
> > DIRECT_NO_TARGET_BUILTIN (asrtgt_d, LARCH_VOID_FTYPE_DI_DI,
> > default),
> > DIRECT_NO_TARGET_BUILTIN (syscall, LARCH_VOID_FTYPE_USI,
> > default),
> > DIRECT_NO_TARGET_BUILTIN (break, LARCH_VOID_FTYPE_USI, default),
> > +
> > + FLOAT_BUILTIN_HIQ (huge_valq, LARCH_BUILTIN_HUGE_VALQ),
> > + FLOAT_BUILTIN_HIQ (infq, LARCH_BUILTIN_INFQ),
> > + FLOAT_BUILTIN_FCQ (fabsq, LARCH_BUILTIN_FABSQ),
> > + FLOAT_BUILTIN_FCQ (copysignq, LARCH_BUILTIN_COPYSIGNQ),
> > + FLOAT_BUILTIN_NNQ (nanq, LARCH_BUILTIN_NANQ),
> > + FLOAT_BUILTIN_NNQ (nansq, LARCH_BUILTIN_NANSQ),
> > +
> > };
> >
> > /* Index I is the function declaration for loongarch_builtins[I],
> > or null if
> > @@ -255,10 +301,13 @@ loongarch_init_builtins (void)
> > const struct loongarch_builtin_description *d;
> > unsigned int i;
> > tree type;
> > + tree const_string_type
> > + =build_pointer_type (build_qualified_type (char_type_node,
> > + TYPE_QUAL_CONST));
> >
> > /* Iterate through all of the bdesc arrays, initializing all of
> > the
> > builtin functions. */
> > - for (i = 0; i < ARRAY_SIZE (loongarch_builtins); i++)
> > + for (i = 0; i < ARRAY_SIZE (loongarch_builtins)-MATHQ_NUMS; i++)
> > {
> > d = &loongarch_builtins[i];
> > if (d->avail ())
> > @@ -270,6 +319,63 @@ loongarch_init_builtins (void)
> > loongarch_get_builtin_decl_index[d->icode] = i;
> > }
> > }
> > + /* Register the type long_double_type_node as a built-in type
> > and
> > + give it an alias "__float128". */
> > + (*lang_hooks.types.register_builtin_type)
> > (long_double_type_node,
> > + "__float128");
> > +
> > + type = build_function_type_list (long_double_type_node,
> > NULL_TREE);
> > + d = &loongarch_builtins[i];
> > + loongarch_builtin_decls[i]
> > + =add_builtin_function ("__builtin_huge_valq", type,
> > + i, BUILT_IN_MD, NULL, NULL_TREE);
> > + loongarch_get_builtin_decl_index[d->icode]=i++;
> > +
> > + type = build_function_type_list (long_double_type_node,
> > NULL_TREE);
> > + d = &loongarch_builtins[i];
> > + loongarch_builtin_decls[i]
> > + =add_builtin_function ("__builtin_infq", type,
> > + i, BUILT_IN_MD, NULL, NULL_TREE);
> > + loongarch_get_builtin_decl_index[d->icode]=i++;
> > +
> > + type = build_function_type_list (long_double_type_node,
> > + long_double_type_node,
> > + NULL_TREE);
> > + d = &loongarch_builtins[i];
> > + loongarch_builtin_decls[i]
> > + =add_builtin_function ("__builtin_fabsq", type,
> > + i, BUILT_IN_MD, NULL, NULL_TREE);
> > + TREE_READONLY (loongarch_builtin_decls[i]) =1;
> > + loongarch_get_builtin_decl_index[d->icode]=i++;
> > +
> > + type = build_function_type_list (long_double_type_node,
> > + long_double_type_node,
> > + long_double_type_node,
> > + NULL_TREE);
> > + d = &loongarch_builtins[i];
> > + loongarch_builtin_decls[i]
> > + =add_builtin_function ("__builtin_copysignq", type,
> > + i, BUILT_IN_MD, NULL, NULL_TREE);
> > + TREE_READONLY (loongarch_builtin_decls[i]) =1;
> > + loongarch_get_builtin_decl_index[d->icode]=i++;
> > +
> > + type=build_function_type_list (long_double_type_node,
> > + const_string_type,
> > + NULL_TREE);
> > + d = &loongarch_builtins[i];
> > + loongarch_builtin_decls[i]
> > + =add_builtin_function ("__builtin_nanq", type,
> > + i, BUILT_IN_MD, "__nanq",
> > NULL_TREE);
> > + TREE_READONLY (loongarch_builtin_decls[i]) =1;
> > + loongarch_get_builtin_decl_index[d->icode]=i++;
> > +
> > + d = &loongarch_builtins[i];
> > + loongarch_builtin_decls[i]
> > + =add_builtin_function ("__builtin_nansq", type,
> > + i, BUILT_IN_MD, "__nansq",
> > NULL_TREE);
> > + TREE_READONLY (loongarch_builtin_decls[i]) =1;
> > + loongarch_get_builtin_decl_index[d->icode]=i;
> > +
> > }
> >
> > /* Implement TARGET_BUILTIN_DECL. */
> > @@ -282,6 +388,42 @@ loongarch_builtin_decl (unsigned int code,
> > bool initialize_p ATTRIBUTE_UNUSED)
> > return loongarch_builtin_decls[code];
> > }
> >
> > +tree
> > +loongarch_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
> > + tree *args, bool ignore ATTRIBUTE_UNUSED)
> > +{
> > + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
> > + {
> > + enum loongarch_function_type fn_code
> > + = (enum loongarch_function_type) DECL_MD_FUNCTION_CODE
> > (fndecl);
> > + switch (fn_code)
> > + {
> > + case LARCH_BUILTIN_NANQ:
> > + case LARCH_BUILTIN_NANSQ:
> > + {
> > + tree type = TREE_TYPE (TREE_TYPE (fndecl));
> > + const char *str = c_getstr (*args);
> > + int quiet = fn_code == LARCH_BUILTIN_NANQ;
> > + REAL_VALUE_TYPE real;
> > +
> > + if (str && real_nan (&real, str, quiet, TYPE_MODE
> > (type)))
> > + return build_real (type, real);
> > + return NULL_TREE;
> > + }
> > +
> > + default:
> > + break;
> > + }
> > + }
> > +
> > +#ifdef SUBTARGET_FOLD_BUILTIN
> > + return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore);
> > +#endif
> > +
> > + return NULL_TREE;
> > +}
> > +
> > +
> > /* Take argument ARGNO from EXP's argument list and convert it
> > into
> > an expand operand. Store the operand in *OP. */
> >
> > @@ -362,11 +504,33 @@ loongarch_expand_builtin (tree exp, rtx
> > target, rtx subtarget ATTRIBUTE_UNUSED,
> > switch (d->builtin_type)
> > {
> > case LARCH_BUILTIN_DIRECT:
> > + case LARCH_BUILTIN_FCQ_DIRECT:
> > return loongarch_expand_builtin_direct (d->icode, target,
> > exp, true);
> >
> > case LARCH_BUILTIN_DIRECT_NO_TARGET:
> > return loongarch_expand_builtin_direct (d->icode, target,
> > exp, false);
> > - }
> > +
> > + case LARCH_BUILTIN_NNQ_DIRECT:
> > + return expand_call ( exp ,target , ignore);
> > +
> > + case LARCH_BUILTIN_HIQ_DIRECT:
> > + {
> > + machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
> > + REAL_VALUE_TYPE inf;
> > + rtx tmp;
> > +
> > + real_inf (&inf);
> > + tmp = const_double_from_real_value (inf, target_mode);
> > +
> > + tmp=validize_mem (force_const_mem (target_mode,tmp));
> > +
> > + if (target ==0)
> > + target =gen_reg_rtx (target_mode);
> > + emit_move_insn (target,tmp);
> > +
> > + return target;
> > + }
> > + }
> > gcc_unreachable ();
> > }
> >
> > diff --git a/gcc/config/loongarch/loongarch-protos.h
> > b/gcc/config/loongarch/loongarch-protos.h
> > index b71b188507a..35fc2ad7def 100644
> > --- a/gcc/config/loongarch/loongarch-protos.h
> > +++ b/gcc/config/loongarch/loongarch-protos.h
> > @@ -175,11 +175,13 @@ extern void
> > loongarch_register_frame_header_opt (void);
> > /* Routines implemented in loongarch-c.c. */
> > void loongarch_cpu_cpp_builtins (cpp_reader *);
> >
> > +extern tree loongarch_fold_builtin (tree, int, tree*, bool);
> > extern void loongarch_init_builtins (void);
> > extern void loongarch_atomic_assign_expand_fenv (tree *, tree *,
> > tree *);
> > extern tree loongarch_builtin_decl (unsigned int, bool);
> > extern rtx loongarch_expand_builtin (tree, rtx, rtx subtarget
> > ATTRIBUTE_UNUSED,
> > machine_mode, int);
> > extern tree loongarch_build_builtin_va_list (void);
> > +extern machine_mode loongarch_c_mode_for_suffix (char suffix);
> >
> > #endif /* ! GCC_LOONGARCH_PROTOS_H */
> > diff --git a/gcc/config/loongarch/loongarch.cc
> > b/gcc/config/loongarch/loongarch.cc
> > index 86d58784113..7a8358c9630 100644
> > --- a/gcc/config/loongarch/loongarch.cc
> > +++ b/gcc/config/loongarch/loongarch.cc
> > @@ -6790,6 +6790,16 @@ loongarch_set_handled_components (sbitmap
> > components)
> > cfun->machine->reg_is_wrapped_separately[regno] = true;
> > }
> >
> > +/* Target hook for c_mode_for_suffix. */
> > +machine_mode
> > +loongarch_c_mode_for_suffix (char suffix)
> > +{
> > + if (suffix == 'q')
> > + return TFmode;
> > +
> > + return VOIDmode;
> > +}
> > +
> > /* Initialize the GCC target structure. */
> > #undef TARGET_ASM_ALIGNED_HI_OP
> > #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
> > @@ -6901,6 +6911,10 @@ loongarch_set_handled_components (sbitmap
> > components)
> > #define TARGET_BUILTIN_DECL loongarch_builtin_decl
> > #undef TARGET_EXPAND_BUILTIN
> > #define TARGET_EXPAND_BUILTIN loongarch_expand_builtin
> > +#undef TARGET_FOLD_BUILTIN
> > +#define TARGET_FOLD_BUILTIN loongarch_fold_builtin
> > +#undef TARGET_C_MODE_FOR_SUFFIX
> > +#define TARGET_C_MODE_FOR_SUFFIX loongarch_c_mode_for_suffix
> >
> > /* The generic ELF target does not always have TLS support. */
> > #ifdef HAVE_AS_TLS
> > diff --git a/gcc/config/loongarch/loongarch.md
> > b/gcc/config/loongarch/loongarch.md
> > index b37e070660f..9fe3faf8b92 100644
> > --- a/gcc/config/loongarch/loongarch.md
> > +++ b/gcc/config/loongarch/loongarch.md
> > @@ -44,6 +44,13 @@ (define_c_enum "unspec" [
> > UNSPEC_FSCALEB
> > UNSPEC_FLOGB
> >
> > + UNSPEC_INFQ
> > + UNSPEC_HUGE_VALQ
> > + UNSPEC_FABSQ
> > + UNSPEC_COPYSIGNQ
> > + UNSPEC_NANQ
> > + UNSPEC_NANSQ
> > +
> > ;; Override return address for exception handling.
> > UNSPEC_EH_RETURN
> >
> > @@ -563,6 +570,15 @@ (define_int_attr bytepick_imm [(8 "1")
> > (48 "6")
> > (56 "7")])
> >
> > +;; mathq function
> > +(define_int_iterator MATHQ[UNSPEC_INFQ UNSPEC_HUGE_VALQ
> > + UNSPEC_NANQ UNSPEC_NANSQ])
> > +(define_int_attr mathq_pattern[(UNSPEC_INFQ "infq")
> > + (UNSPEC_HUGE_VALQ "huge_valq")
> > + (UNSPEC_NANQ "nanq")
> > + (UNSPEC_NANSQ "nansq")]
> > +)
> > +
> > ;;
> > ;; ....................
> > ;;
> > @@ -2008,6 +2024,59 @@ (define_insn "movfcc"
> > ""
> > "movgr2cf\t%0,$r0")
> >
> > +;; Implements functions with a "q" suffix
> > +
> > +(define_insn "<mathq_pattern>"
> > + [(unspec:SI[(const_int 0)] MATHQ)]
> > + ""
> > + "")
> > +
> > +;;Implement __builtin_fabsq function.
> > +
> > +(define_insn_and_split "fabsq"
> > + [(set (match_operand:TF 0 "register_operand" "=r")
> > + (unspec:TF[(match_operand:TF 1 "register_operand" "rG")]
> > + UNSPEC_FABSQ))]
> > + ""
> > + "#"
> > + "reload_completed"
> > +[(set (zero_extract:DI (match_operand:DI 0 "register_operand")
> > + (match_operand:SI 3 "const_int_operand")
> > + (match_operand:SI 4 "const_int_operand"))
> > + (match_operand:DI 2 "const_int_operand"))]
> > +{
> > + operands[0] = gen_rtx_REG (Pmode, REGNO (operands[0])+1);
> > + operands[2] = GEN_INT (0);
> > + operands[3] = GEN_INT (1);
> > + operands[4] = GEN_INT (63);
> > +}
> > +)
> > +
> > +;;Implement __builtin_copysignq function.
> > +
> > +(define_insn_and_split "copysignq"
> > + [(set (match_operand:TF 0 "register_operand" "=r")
> > + (unspec:TF[(match_operand:TF 1 "register_operand" "rG")
> > + (match_operand:TF 2 "register_operand" "rG")]
> > + UNSPEC_COPYSIGNQ))]
> > + ""
> > + "#"
> > + "reload_completed"
> > + [(set (match_operand:DI 2 "register_operand")
> > + (lshiftrt :DI (match_operand:DI 2 "register_operand")
> > + (match_operand:SI 4 "arith_operand")))
> > + (set (zero_extract:DI (match_operand:DI 0 "register_operand")
> > + (match_operand:SI 3 "const_int_operand")
> > + (match_operand:SI 4 "const_int_operand"))
> > + (match_operand:DI 2 "register_operand"))]
> > +{
> > + operands[0] = gen_rtx_REG (Pmode,REGNO (operands[0])+1);
> > + operands[2] = gen_rtx_REG (Pmode,REGNO (operands[2])+1);
> > + operands[3] = GEN_INT (1);
> > + operands[4] = GEN_INT (63);
> > +}
> > +)
> > +
> > ;; Conditional move instructions.
> >
> > (define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
> > diff --git a/libgcc/config/loongarch/t-softfp-tf
> > b/libgcc/config/loongarch/t-softfp-tf
> > index 306677b1255..0e7c2b4cabe 100644
> > --- a/libgcc/config/loongarch/t-softfp-tf
> > +++ b/libgcc/config/loongarch/t-softfp-tf
> > @@ -1,3 +1,6 @@
> > softfp_float_modes += tf
> > softfp_extensions += sftf dftf
> > softfp_truncations += tfsf tfdf
> > +#Used to implement a special 128-bit function with a q suffix
> > +LIB2ADD += $(srcdir)/config/loongarch/tf-signs.c
> > +
> > diff --git a/libgcc/config/loongarch/tf-signs.c
> > b/libgcc/config/loongarch/tf-signs.c
> > new file mode 100644
> > index 00000000000..68db1729372
> > --- /dev/null
> > +++ b/libgcc/config/loongarch/tf-signs.c
> > @@ -0,0 +1,59 @@
> > +/* Copyright (C) 2008-2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it
> > under
> > +the terms of the GNU General Public License as published by the
> > Free
> > +Software Foundation; either version 3, or (at your option) any
> > later
> > +version.
> > +
> > +GCC 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 General Public
> > License
> > +for more details.
> > +
> > +Under Section 7 of GPL version 3, you are granted additional
> > +permissions described in the GCC Runtime Library Exception,
> > version
> > +3.1, as published by the Free Software Foundation.
> > +
> > +You should have received a copy of the GNU General Public License
> > and
> > +a copy of the GCC Runtime Library Exception along with this
> > program;
> > +see the files COPYING3 and COPYING.RUNTIME respectively. If not,
> > see
> > +<http://www.gnu.org/licenses/>;. */
> > +
> > +union _FP_UNION_Q
> > +{
> > + __float128 flt;
> > + struct
> > + {
> > + unsigned long frac0 : 64;
> > + unsigned long frac1 : 48;
> > + unsigned exp : 15;
> > + unsigned sign : 1;
> > + } bits __attribute__((packed));
> > +};
> > +
> > +__float128 __nanq (const char *str);
> > +__float128 __nansq (const char *str);
> > +
> > +__float128 __nanq (const char * str)
> > +{
> > + union _FP_UNION_Q nan;
> > + nan.bits.frac0 = 0;
> > + nan.bits.frac1 = 0;
> > + nan.bits.exp = 0x7FFF;
> > + nan.bits.sign = 0;
> > +
> > + return nan.flt;
> > +}
> > +__float128 __nansq (const char *str)
> > +{
> > + union _FP_UNION_Q nan;
> > + nan.bits.frac0 = 0xFFFFFFFFFFFFFFFFUL;
> > + nan.bits.frac1 = 0x0000FFFFFFFFFFFFUL;
> > + nan.bits.exp = 0x7FFF;
> > + nan.bits.sign = 0;
> > +
> > + return nan.flt;
> > +}
> > +
On Thu, 17 Aug 2023, Xi Ruoyao via Gcc-patches wrote:
> So I guess we just need
>
> builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> builtin_define ("__builtin_nanq=__builtin_nanf128");
>
> etc. to map the "q" builtins to "f128" builtins if we really need the
> "q" builtins.
>
> Joseph: the problem here is many customers of LoongArch CPUs wish to
> compile their old code with minimal change. Is it acceptable to add
> these builtin_define's like rs6000-c.cc? Note "a new architecture" does
> not mean we'll only compile post-C2x-era programs onto it.
The powerpc support for __float128 started in GCC 6, predating the support
for _FloatN type names, built-in functions etc. in GCC 7 - that's why
there's such backwards compatibility support there. That name only exists
on a few architectures.
If people really want to compile code using the old __float128 names for
LoongArch I suppose you could have such #defines, but it would be better
for people to make their code use the standard names (as supported from
GCC 7 onwards, though only from GCC 13 in C++) and then put backwards
compatibility in their code for using the __float128 names if they want to
support the type with older GCC (GCC 6 or before for C; GCC 12 or before
for C++) on x86_64 / i386 / powerpc / ia64. Such backwards compatibility
in user code is more likely to be relevant for C++ than for C, given how
the C++ support was added to GCC much more recently. (Note: I haven't
checked when other compilers added support for the _Float128 name or
associated built-in functions, whether for C or for C++, which might also
affect when user code wants such compatibility.)
在 2023-08-17四的 15:08 +0000,Joseph Myers写道:
> On Thu, 17 Aug 2023, Xi Ruoyao via Gcc-patches wrote:
>
> > So I guess we just need
> >
> > builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> > builtin_define ("__builtin_nanq=__builtin_nanf128");
> >
> > etc. to map the "q" builtins to "f128" builtins if we really need
> > the
> > "q" builtins.
> >
> > Joseph: the problem here is many customers of LoongArch CPUs wish
> > to
> > compile their old code with minimal change. Is it acceptable to
> > add
> > these builtin_define's like rs6000-c.cc? Note "a new architecture"
> > does
> > not mean we'll only compile post-C2x-era programs onto it.
>
> The powerpc support for __float128 started in GCC 6, predating the
> support
> for _FloatN type names, built-in functions etc. in GCC 7 - that's
> why
> there's such backwards compatibility support there. That name only
> exists
> on a few architectures.
>
> If people really want to compile code using the old __float128 names
> for
> LoongArch I suppose you could have such #defines, but it would be
> better
> for people to make their code use the standard names (as supported
> from
> GCC 7 onwards, though only from GCC 13 in C++) and then put
> backwards
> compatibility in their code for using the __float128 names if they
> want to
> support the type with older GCC (GCC 6 or before for C; GCC 12 or
> before
> for C++) on x86_64 / i386 / powerpc / ia64. Such backwards
> compatibility
> in user code is more likely to be relevant for C++ than for C, given
> how
> the C++ support was added to GCC much more recently. (Note: I
> haven't
> checked when other compilers added support for the _Float128 name or
> associated built-in functions, whether for C or for C++, which might
> also
> affect when user code wants such compatibility.)
>
Thank you for your valuable comments. On the LoongArch architecture,
the "__float128" type is associated with float128_type_node and the "q"
suffix function is mapped to the "f128" function. This allows
compatibility with both "__float128" and "_Float128" types in the GCC
compiler. The new code is modified as follows:
Add the following to the loongarch-builtins.c file:
+lang_hooks.types.register_builtin_type (float128_type_node,
"__float128");
Add the following to the loongarch-c.c file:
+builtin_define ("__builtin_fabsq=__builtin_fabsf128");
+builtin_define ("__builtin_copysignq=__builtin_copysignf128");
+builtin_define ("__builtin_nanq=__builtin_nanf128");
+builtin_define ("__builtin_nansq=__builtin_nansf128");
+builtin_define ("__builtin_infq=__builtin_inff128");
+builtin_define ("__builtin_huge_valq=__builtin_huge_valf128");
The regression tests of the six functions were added without problems.
However, the implementation of the __builtin_nansq() function does not
get the result we want. The questions are as follows:
x86_64:
_Float128 ret=__builtin_nansf128("NAN");
compiled to (with gcc test.c -O2 ):
.cfi_offset 1, -8
bl %plt(__builtin_nansf128)
..
LoongArch:
_Float128 ret=__builtin_nansf128("NAN");
compiled to (with gcc test.c -O2 ):
.cfi_offset 1, -8
bl %plt(__builtin_nansf128)
..
Obviously, there may have been legacy issues with the implementation
when "_Float128 __builtin_nansf128()" was first supported.
Architectures including LoongArch, x86_64, arm, etc. are no longer
supported, and some of the remaining architectures are unproven.
I will continue to follow up the implementation of the builtin
function and complete the function.
On Fri, 2023-08-18 at 14:39 +0800, chenxiaolong wrote:
> 在 2023-08-17四的 15:08 +0000,Joseph Myers写道:
> > On Thu, 17 Aug 2023, Xi Ruoyao via Gcc-patches wrote:
> >
> > > So I guess we just need
> > >
> > > builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> > > builtin_define ("__builtin_nanq=__builtin_nanf128");
> > >
> > > etc. to map the "q" builtins to "f128" builtins if we really need
> > > the
> > > "q" builtins.
> > >
> > > Joseph: the problem here is many customers of LoongArch CPUs wish
> > > to
> > > compile their old code with minimal change. Is it acceptable to
> > > add
> > > these builtin_define's like rs6000-c.cc? Note "a new architecture"
> > > does
> > > not mean we'll only compile post-C2x-era programs onto it.
> >
> > The powerpc support for __float128 started in GCC 6, predating the
> > support
> > for _FloatN type names, built-in functions etc. in GCC 7 - that's
> > why
> > there's such backwards compatibility support there. That name only
> > exists
> > on a few architectures.
> >
> > If people really want to compile code using the old __float128 names
> > for
> > LoongArch I suppose you could have such #defines, but it would be
> > better
> > for people to make their code use the standard names (as supported
> > from
> > GCC 7 onwards, though only from GCC 13 in C++) and then put
> > backwards
> > compatibility in their code for using the __float128 names if they
> > want to
> > support the type with older GCC (GCC 6 or before for C; GCC 12 or
> > before
> > for C++) on x86_64 / i386 / powerpc / ia64. Such backwards
> > compatibility
> > in user code is more likely to be relevant for C++ than for C, given
> > how
> > the C++ support was added to GCC much more recently. (Note: I
> > haven't
> > checked when other compilers added support for the _Float128 name or
> > associated built-in functions, whether for C or for C++, which might
> > also
> > affect when user code wants such compatibility.)
> >
> Thank you for your valuable comments. On the LoongArch architecture,
> the "__float128" type is associated with float128_type_node and the "q"
> suffix function is mapped to the "f128" function. This allows
> compatibility with both "__float128" and "_Float128" types in the GCC
> compiler. The new code is modified as follows:
> Add the following to the loongarch-builtins.c file:
> +lang_hooks.types.register_builtin_type (float128_type_node,
> "__float128");
> Add the following to the loongarch-c.c file:
> +builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> +builtin_define ("__builtin_copysignq=__builtin_copysignf128");
> +builtin_define ("__builtin_nanq=__builtin_nanf128");
> +builtin_define ("__builtin_nansq=__builtin_nansf128");
> +builtin_define ("__builtin_infq=__builtin_inff128");
> +builtin_define ("__builtin_huge_valq=__builtin_huge_valf128");
>
> The regression tests of the six functions were added without problems.
> However, the implementation of the __builtin_nansq() function does not
> get the result we want. The questions are as follows:
> x86_64:
> _Float128 ret=__builtin_nansf128("NAN");
>
> compiled to (with gcc test.c -O2 ):
> .cfi_offset 1, -8
> bl %plt(__builtin_nansf128)
> ..
> LoongArch:
> _Float128 ret=__builtin_nansf128("NAN");
> compiled to (with gcc test.c -O2 ):
> .cfi_offset 1, -8
> bl %plt(__builtin_nansf128)
It seems wrong. It should be "bl %plt(nansf128)" instead, without the
__builtin_ prefix so the implementation in libm (from Glibc) will be
used instead. AFAIK __builtin_nan and __builtin_nans are rarely called
with a non-empty tagp so it's not worthy to inline the implementation
for non-empty tagp here.
The same issue happens on x86_64:
call __builtin_nansf128@PLT
__builtin_nanf128 compiles correct:
call nanf128@PLT
I'll see if there is a ticket in https://gcc.gnu.org/bugzilla. If not
I'll create one.
On Fri, 2023-08-18 at 14:58 +0800, Xi Ruoyao via Gcc-patches wrote:
> On Fri, 2023-08-18 at 14:39 +0800, chenxiaolong wrote:
> > 在 2023-08-17四的 15:08 +0000,Joseph Myers写道:
> > > On Thu, 17 Aug 2023, Xi Ruoyao via Gcc-patches wrote:
> > >
> > > > So I guess we just need
> > > >
> > > > builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> > > > builtin_define ("__builtin_nanq=__builtin_nanf128");
> > > >
> > > > etc. to map the "q" builtins to "f128" builtins if we really need
> > > > the
> > > > "q" builtins.
> > > >
> > > > Joseph: the problem here is many customers of LoongArch CPUs wish
> > > > to
> > > > compile their old code with minimal change. Is it acceptable to
> > > > add
> > > > these builtin_define's like rs6000-c.cc? Note "a new architecture"
> > > > does
> > > > not mean we'll only compile post-C2x-era programs onto it.
> > >
> > > The powerpc support for __float128 started in GCC 6, predating the
> > > support
> > > for _FloatN type names, built-in functions etc. in GCC 7 - that's
> > > why
> > > there's such backwards compatibility support there. That name only
> > > exists
> > > on a few architectures.
> > >
> > > If people really want to compile code using the old __float128 names
> > > for
> > > LoongArch I suppose you could have such #defines, but it would be
> > > better
> > > for people to make their code use the standard names (as supported
> > > from
> > > GCC 7 onwards, though only from GCC 13 in C++) and then put
> > > backwards
> > > compatibility in their code for using the __float128 names if they
> > > want to
> > > support the type with older GCC (GCC 6 or before for C; GCC 12 or
> > > before
> > > for C++) on x86_64 / i386 / powerpc / ia64. Such backwards
> > > compatibility
> > > in user code is more likely to be relevant for C++ than for C, given
> > > how
> > > the C++ support was added to GCC much more recently. (Note: I
> > > haven't
> > > checked when other compilers added support for the _Float128 name or
> > > associated built-in functions, whether for C or for C++, which might
> > > also
> > > affect when user code wants such compatibility.)
> > >
> > Thank you for your valuable comments. On the LoongArch architecture,
> > the "__float128" type is associated with float128_type_node and the "q"
> > suffix function is mapped to the "f128" function. This allows
> > compatibility with both "__float128" and "_Float128" types in the GCC
> > compiler. The new code is modified as follows:
> > Add the following to the loongarch-builtins.c file:
> > +lang_hooks.types.register_builtin_type (float128_type_node,
> > "__float128");
> > Add the following to the loongarch-c.c file:
> > +builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> > +builtin_define ("__builtin_copysignq=__builtin_copysignf128");
> > +builtin_define ("__builtin_nanq=__builtin_nanf128");
> > +builtin_define ("__builtin_nansq=__builtin_nansf128");
> > +builtin_define ("__builtin_infq=__builtin_inff128");
> > +builtin_define ("__builtin_huge_valq=__builtin_huge_valf128");
> >
> > The regression tests of the six functions were added without problems.
> > However, the implementation of the __builtin_nansq() function does not
> > get the result we want. The questions are as follows:
> > x86_64:
> > _Float128 ret=__builtin_nansf128("NAN");
> >
> > compiled to (with gcc test.c -O2 ):
> > .cfi_offset 1, -8
> > bl %plt(__builtin_nansf128)
> > ..
> > LoongArch:
> > _Float128 ret=__builtin_nansf128("NAN");
> > compiled to (with gcc test.c -O2 ):
> > .cfi_offset 1, -8
> > bl %plt(__builtin_nansf128)
>
> It seems wrong. It should be "bl %plt(nansf128)" instead, without the
> __builtin_ prefix so the implementation in libm (from Glibc) will be
> used instead. AFAIK __builtin_nan and __builtin_nans are rarely called
> with a non-empty tagp so it's not worthy to inline the implementation
> for non-empty tagp here.
>
> The same issue happens on x86_64:
>
> call __builtin_nansf128@PLT
>
> __builtin_nanf128 compiles correct:
>
> call nanf128@PLT
>
> I'll see if there is a ticket in https://gcc.gnu.org/bugzilla. If not
> I'll create one.
Alright, Glibc does not have a "nansf128" function yet. Actually there
is even no "nans" function for the plain double type. So even a plain
__builtin_nans("114") won't work too.
If we'll fix this, we need to do it in a generic, target-independent way
(i. e. fix it all at once for all targets).
So for now, and for LoongArch specific code, the proper thing to do is
aliasing float128_type_node as __float128 and the six
__builtin_define's.
Please commit them to trunk if regression test passes. You need to also
add LoongArch as a target supporting __float128 in extend.texi.
On Fri, 2023-08-18 at 15:05 +0800, Xi Ruoyao via Gcc-patches wrote:
> On Fri, 2023-08-18 at 14:58 +0800, Xi Ruoyao via Gcc-patches wrote:
> > On Fri, 2023-08-18 at 14:39 +0800, chenxiaolong wrote:
> > > 在 2023-08-17四的 15:08 +0000,Joseph Myers写道:
> > > > On Thu, 17 Aug 2023, Xi Ruoyao via Gcc-patches wrote:
> > > >
> > > > > So I guess we just need
> > > > >
> > > > > builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> > > > > builtin_define ("__builtin_nanq=__builtin_nanf128");
> > > > >
> > > > > etc. to map the "q" builtins to "f128" builtins if we really need
> > > > > the
> > > > > "q" builtins.
> > > > >
> > > > > Joseph: the problem here is many customers of LoongArch CPUs wish
> > > > > to
> > > > > compile their old code with minimal change. Is it acceptable to
> > > > > add
> > > > > these builtin_define's like rs6000-c.cc? Note "a new architecture"
> > > > > does
> > > > > not mean we'll only compile post-C2x-era programs onto it.
> > > >
> > > > The powerpc support for __float128 started in GCC 6, predating the
> > > > support
> > > > for _FloatN type names, built-in functions etc. in GCC 7 - that's
> > > > why
> > > > there's such backwards compatibility support there. That name only
> > > > exists
> > > > on a few architectures.
> > > >
> > > > If people really want to compile code using the old __float128 names
> > > > for
> > > > LoongArch I suppose you could have such #defines, but it would be
> > > > better
> > > > for people to make their code use the standard names (as supported
> > > > from
> > > > GCC 7 onwards, though only from GCC 13 in C++) and then put
> > > > backwards
> > > > compatibility in their code for using the __float128 names if they
> > > > want to
> > > > support the type with older GCC (GCC 6 or before for C; GCC 12 or
> > > > before
> > > > for C++) on x86_64 / i386 / powerpc / ia64. Such backwards
> > > > compatibility
> > > > in user code is more likely to be relevant for C++ than for C, given
> > > > how
> > > > the C++ support was added to GCC much more recently. (Note: I
> > > > haven't
> > > > checked when other compilers added support for the _Float128 name or
> > > > associated built-in functions, whether for C or for C++, which might
> > > > also
> > > > affect when user code wants such compatibility.)
> > > >
> > > Thank you for your valuable comments. On the LoongArch architecture,
> > > the "__float128" type is associated with float128_type_node and the "q"
> > > suffix function is mapped to the "f128" function. This allows
> > > compatibility with both "__float128" and "_Float128" types in the GCC
> > > compiler. The new code is modified as follows:
> > > Add the following to the loongarch-builtins.c file:
> > > +lang_hooks.types.register_builtin_type (float128_type_node,
> > > "__float128");
> > > Add the following to the loongarch-c.c file:
> > > +builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> > > +builtin_define ("__builtin_copysignq=__builtin_copysignf128");
> > > +builtin_define ("__builtin_nanq=__builtin_nanf128");
> > > +builtin_define ("__builtin_nansq=__builtin_nansf128");
> > > +builtin_define ("__builtin_infq=__builtin_inff128");
> > > +builtin_define ("__builtin_huge_valq=__builtin_huge_valf128");
> > >
> > > The regression tests of the six functions were added without problems.
> > > However, the implementation of the __builtin_nansq() function does not
> > > get the result we want. The questions are as follows:
> > > x86_64:
> > > _Float128 ret=__builtin_nansf128("NAN");
> > >
> > > compiled to (with gcc test.c -O2 ):
> > > .cfi_offset 1, -8
> > > bl %plt(__builtin_nansf128)
> > > ..
> > > LoongArch:
> > > _Float128 ret=__builtin_nansf128("NAN");
> > > compiled to (with gcc test.c -O2 ):
> > > .cfi_offset 1, -8
> > > bl %plt(__builtin_nansf128)
> >
> > It seems wrong. It should be "bl %plt(nansf128)" instead, without the
> > __builtin_ prefix so the implementation in libm (from Glibc) will be
> > used instead. AFAIK __builtin_nan and __builtin_nans are rarely called
> > with a non-empty tagp so it's not worthy to inline the implementation
> > for non-empty tagp here.
> >
> > The same issue happens on x86_64:
> >
> > call __builtin_nansf128@PLT
> >
> > __builtin_nanf128 compiles correct:
> >
> > call nanf128@PLT
> >
> > I'll see if there is a ticket in https://gcc.gnu.org/bugzilla. If not
> > I'll create one.
https://gcc.gnu.org/PR111058
> Alright, Glibc does not have a "nansf128" function yet. Actually there
> is even no "nans" function for the plain double type. So even a plain
> __builtin_nans("114") won't work too.
>
> If we'll fix this, we need to do it in a generic, target-independent way
> (i. e. fix it all at once for all targets).
>
> So for now, and for LoongArch specific code, the proper thing to do is
> aliasing float128_type_node as __float128 and the six
> __builtin_define's.
>
> Please commit them to trunk if regression test passes. You need to also
> add LoongArch as a target supporting __float128 in extend.texi.
在 2023-08-18五的 15:19 +0800,Xi Ruoyao写道:
> On Fri, 2023-08-18 at 15:05 +0800, Xi Ruoyao via Gcc-patches wrote:
> > On Fri, 2023-08-18 at 14:58 +0800, Xi Ruoyao via Gcc-patches wrote:
> > > On Fri, 2023-08-18 at 14:39 +0800, chenxiaolong wrote:
> > > > 在 2023-08-17四的 15:08 +0000,Joseph Myers写道:
> > > > > On Thu, 17 Aug 2023, Xi Ruoyao via Gcc-patches wrote:
> > > > >
> > > > > > So I guess we just need
> > > > > >
> > > > > > builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> > > > > > builtin_define ("__builtin_nanq=__builtin_nanf128");
> > > > > >
> > > > > > etc. to map the "q" builtins to "f128" builtins if we
> > > > > > really need
> > > > > > the
> > > > > > "q" builtins.
> > > > > >
> > > > > > Joseph: the problem here is many customers of LoongArch
> > > > > > CPUs wish
> > > > > > to
> > > > > > compile their old code with minimal change. Is it
> > > > > > acceptable to
> > > > > > add
> > > > > > these builtin_define's like rs6000-c.cc? Note "a new
> > > > > > architecture"
> > > > > > does
> > > > > > not mean we'll only compile post-C2x-era programs onto it.
> > > > >
> > > > > The powerpc support for __float128 started in GCC 6,
> > > > > predating the
> > > > > support
> > > > > for _FloatN type names, built-in functions etc. in GCC 7 -
> > > > > that's
> > > > > why
> > > > > there's such backwards compatibility support there. That
> > > > > name only
> > > > > exists
> > > > > on a few architectures.
> > > > >
> > > > > If people really want to compile code using the old
> > > > > __float128 names
> > > > > for
> > > > > LoongArch I suppose you could have such #defines, but it
> > > > > would be
> > > > > better
> > > > > for people to make their code use the standard names (as
> > > > > supported
> > > > > from
> > > > > GCC 7 onwards, though only from GCC 13 in C++) and then put
> > > > > backwards
> > > > > compatibility in their code for using the __float128 names if
> > > > > they
> > > > > want to
> > > > > support the type with older GCC (GCC 6 or before for C; GCC
> > > > > 12 or
> > > > > before
> > > > > for C++) on x86_64 / i386 / powerpc / ia64. Such backwards
> > > > > compatibility
> > > > > in user code is more likely to be relevant for C++ than for
> > > > > C, given
> > > > > how
> > > > > the C++ support was added to GCC much more recently. (Note:
> > > > > I
> > > > > haven't
> > > > > checked when other compilers added support for the _Float128
> > > > > name or
> > > > > associated built-in functions, whether for C or for C++,
> > > > > which might
> > > > > also
> > > > > affect when user code wants such compatibility.)
> > > > >
> > > > Thank you for your valuable comments. On the LoongArch
> > > > architecture,
> > > > the "__float128" type is associated with float128_type_node and
> > > > the "q"
> > > > suffix function is mapped to the "f128" function. This allows
> > > > compatibility with both "__float128" and "_Float128" types in
> > > > the GCC
> > > > compiler. The new code is modified as follows:
> > > > Add the following to the loongarch-builtins.c file:
> > > > +lang_hooks.types.register_builtin_type (float128_type_node,
> > > > "__float128");
> > > > Add the following to the loongarch-c.c file:
> > > > +builtin_define ("__builtin_fabsq=__builtin_fabsf128");
> > > > +builtin_define ("__builtin_copysignq=__builtin_copysignf128");
> > > > +builtin_define ("__builtin_nanq=__builtin_nanf128");
> > > > +builtin_define ("__builtin_nansq=__builtin_nansf128");
> > > > +builtin_define ("__builtin_infq=__builtin_inff128");
> > > > +builtin_define ("__builtin_huge_valq=__builtin_huge_valf128");
> > > >
> > > > The regression tests of the six functions were added without
> > > > problems.
> > > > However, the implementation of the __builtin_nansq() function
> > > > does not
> > > > get the result we want. The questions are as follows:
> > > > x86_64:
> > > > _Float128 ret=__builtin_nansf128("NAN");
> > > >
> > > > compiled to (with gcc test.c -O2 ):
> > > > .cfi_offset 1, -8
> > > > bl %plt(__builtin_nansf128)
> > > > ..
> > > > LoongArch:
> > > > _Float128 ret=__builtin_nansf128("NAN");
> > > > compiled to (with gcc test.c -O2 ):
> > > > .cfi_offset 1, -8
> > > > bl %plt(__builtin_nansf128)
> > >
> > > It seems wrong. It should be "bl %plt(nansf128)" instead,
> > > without the
> > > __builtin_ prefix so the implementation in libm (from Glibc) will
> > > be
> > > used instead. AFAIK __builtin_nan and __builtin_nans are rarely
> > > called
> > > with a non-empty tagp so it's not worthy to inline the
> > > implementation
> > > for non-empty tagp here.
> > >
> > > The same issue happens on x86_64:
> > >
> > > call __builtin_nansf128@PLT
> > >
> > > __builtin_nanf128 compiles correct:
> > >
> > > call nanf128@PLT
> > >
> > > I'll see if there is a ticket in https://gcc.gnu.org/bugzilla.
> > > If not
> > > I'll create one.
>
> https://gcc.gnu.org/PR111058
>
> > Alright, Glibc does not have a "nansf128" function yet. Actually
> > there
> > is even no "nans" function for the plain double type. So even a
> > plain
> > __builtin_nans("114") won't work too.
> >
> > If we'll fix this, we need to do it in a generic, target-
> > independent way
> > (i. e. fix it all at once for all targets).
> >
> > So for now, and for LoongArch specific code, the proper thing to do
> > is
> > aliasing float128_type_node as __float128 and the six
> > __builtin_define's.
> >
> > Please commit them to trunk if regression test passes. You need to
> > also
> > add LoongArch as a target supporting __float128 in extend.texi.
Ok, I will properly analyze the implementation of the buildin relatedfunctions and fix this issue as soon as possible.
@@ -36,6 +36,8 @@ along with GCC; see the file COPYING3. If not see
#include "fold-const.h"
#include "expr.h"
#include "langhooks.h"
+#include "calls.h"
+#include "explow.h"
/* Macros to create an enumeration identifier for a function prototype. */
#define LARCH_FTYPE_NAME1(A, B) LARCH_##A##_FTYPE_##B
@@ -48,9 +50,18 @@ enum loongarch_function_type
#define DEF_LARCH_FTYPE(NARGS, LIST) LARCH_FTYPE_NAME##NARGS LIST,
#include "config/loongarch/loongarch-ftypes.def"
#undef DEF_LARCH_FTYPE
+ LARCH_BUILTIN_HUGE_VALQ,
+ LARCH_BUILTIN_INFQ,
+ LARCH_BUILTIN_FABSQ,
+ LARCH_BUILTIN_COPYSIGNQ,
+ LARCH_BUILTIN_NANQ,
+ LARCH_BUILTIN_NANSQ,
LARCH_MAX_FTYPE_MAX
};
+/* Count the number of functions with "q" as the suffix. */
+const int MATHQ_NUMS = (int)LARCH_MAX_FTYPE_MAX - (int)LARCH_BUILTIN_HUGE_VALQ;
+
/* Specifies how a built-in function should be converted into rtl. */
enum loongarch_builtin_type
{
@@ -63,6 +74,15 @@ enum loongarch_builtin_type
value and the arguments are mapped to operands 0 and above. */
LARCH_BUILTIN_DIRECT_NO_TARGET,
+ /* The function corresponds to __builtin_{huge_valq,infq}. */
+ LARCH_BUILTIN_HIQ_DIRECT,
+
+ /* The function corresponds to __builtin_{fabsq,copysignq}. */
+ LARCH_BUILTIN_FCQ_DIRECT,
+
+ /* Define the type of the __builtin_{nanq,nansq} function. */
+ LARCH_BUILTIN_NNQ_DIRECT
+
};
/* Declare an availability predicate for built-in functions that require
@@ -136,6 +156,24 @@ AVAIL_ALL (hard_float, TARGET_HARD_FLOAT_ABI)
LARCH_BUILTIN (INSN, #INSN, LARCH_BUILTIN_DIRECT_NO_TARGET, \
FUNCTION_TYPE, AVAIL)
+/* Define an float to do funciton {huge_valq,infq}. */
+#define FLOAT_BUILTIN_HIQ (INSN, FUNCTION_TYPE) \
+ { CODE_FOR_ ## INSN, \
+ "__builtin_" #INSN, LARCH_BUILTIN_HIQ_DIRECT, \
+ FUNCTION_TYPE, loongarch_builtin_avail_default }
+
+/* Define an float to do funciton {fabsq,copysignq}. */
+#define FLOAT_BUILTIN_FCQ (INSN, FUNCTION_TYPE) \
+ { CODE_FOR_ ## INSN, \
+ "__builtin_" #INSN, LARCH_BUILTIN_FCQ_DIRECT, \
+ FUNCTION_TYPE, loongarch_builtin_avail_default }
+
+/* Define an float to do funciton {nanq,nansq}. */
+#define FLOAT_BUILTIN_NNQ (INSN, FUNCTION_TYPE) \
+ { CODE_FOR_ ## INSN, \
+ "__builtin_" #INSN, LARCH_BUILTIN_NNQ_DIRECT, \
+ FUNCTION_TYPE, loongarch_builtin_avail_default }
+
static const struct loongarch_builtin_description loongarch_builtins[] = {
#define LARCH_MOVFCSR2GR 0
DIRECT_BUILTIN (movfcsr2gr, LARCH_USI_FTYPE_UQI, hard_float),
@@ -183,6 +221,14 @@ static const struct loongarch_builtin_description loongarch_builtins[] = {
DIRECT_NO_TARGET_BUILTIN (asrtgt_d, LARCH_VOID_FTYPE_DI_DI, default),
DIRECT_NO_TARGET_BUILTIN (syscall, LARCH_VOID_FTYPE_USI, default),
DIRECT_NO_TARGET_BUILTIN (break, LARCH_VOID_FTYPE_USI, default),
+
+ FLOAT_BUILTIN_HIQ (huge_valq, LARCH_BUILTIN_HUGE_VALQ),
+ FLOAT_BUILTIN_HIQ (infq, LARCH_BUILTIN_INFQ),
+ FLOAT_BUILTIN_FCQ (fabsq, LARCH_BUILTIN_FABSQ),
+ FLOAT_BUILTIN_FCQ (copysignq, LARCH_BUILTIN_COPYSIGNQ),
+ FLOAT_BUILTIN_NNQ (nanq, LARCH_BUILTIN_NANQ),
+ FLOAT_BUILTIN_NNQ (nansq, LARCH_BUILTIN_NANSQ),
+
};
/* Index I is the function declaration for loongarch_builtins[I], or null if
@@ -255,10 +301,13 @@ loongarch_init_builtins (void)
const struct loongarch_builtin_description *d;
unsigned int i;
tree type;
+ tree const_string_type
+ =build_pointer_type (build_qualified_type (char_type_node,
+ TYPE_QUAL_CONST));
/* Iterate through all of the bdesc arrays, initializing all of the
builtin functions. */
- for (i = 0; i < ARRAY_SIZE (loongarch_builtins); i++)
+ for (i = 0; i < ARRAY_SIZE (loongarch_builtins)-MATHQ_NUMS; i++)
{
d = &loongarch_builtins[i];
if (d->avail ())
@@ -270,6 +319,63 @@ loongarch_init_builtins (void)
loongarch_get_builtin_decl_index[d->icode] = i;
}
}
+ /* Register the type long_double_type_node as a built-in type and
+ give it an alias "__float128". */
+ (*lang_hooks.types.register_builtin_type) (long_double_type_node,
+ "__float128");
+
+ type = build_function_type_list (long_double_type_node, NULL_TREE);
+ d = &loongarch_builtins[i];
+ loongarch_builtin_decls[i]
+ =add_builtin_function ("__builtin_huge_valq", type,
+ i, BUILT_IN_MD, NULL, NULL_TREE);
+ loongarch_get_builtin_decl_index[d->icode]=i++;
+
+ type = build_function_type_list (long_double_type_node, NULL_TREE);
+ d = &loongarch_builtins[i];
+ loongarch_builtin_decls[i]
+ =add_builtin_function ("__builtin_infq", type,
+ i, BUILT_IN_MD, NULL, NULL_TREE);
+ loongarch_get_builtin_decl_index[d->icode]=i++;
+
+ type = build_function_type_list (long_double_type_node,
+ long_double_type_node,
+ NULL_TREE);
+ d = &loongarch_builtins[i];
+ loongarch_builtin_decls[i]
+ =add_builtin_function ("__builtin_fabsq", type,
+ i, BUILT_IN_MD, NULL, NULL_TREE);
+ TREE_READONLY (loongarch_builtin_decls[i]) =1;
+ loongarch_get_builtin_decl_index[d->icode]=i++;
+
+ type = build_function_type_list (long_double_type_node,
+ long_double_type_node,
+ long_double_type_node,
+ NULL_TREE);
+ d = &loongarch_builtins[i];
+ loongarch_builtin_decls[i]
+ =add_builtin_function ("__builtin_copysignq", type,
+ i, BUILT_IN_MD, NULL, NULL_TREE);
+ TREE_READONLY (loongarch_builtin_decls[i]) =1;
+ loongarch_get_builtin_decl_index[d->icode]=i++;
+
+ type=build_function_type_list (long_double_type_node,
+ const_string_type,
+ NULL_TREE);
+ d = &loongarch_builtins[i];
+ loongarch_builtin_decls[i]
+ =add_builtin_function ("__builtin_nanq", type,
+ i, BUILT_IN_MD, "__nanq", NULL_TREE);
+ TREE_READONLY (loongarch_builtin_decls[i]) =1;
+ loongarch_get_builtin_decl_index[d->icode]=i++;
+
+ d = &loongarch_builtins[i];
+ loongarch_builtin_decls[i]
+ =add_builtin_function ("__builtin_nansq", type,
+ i, BUILT_IN_MD, "__nansq", NULL_TREE);
+ TREE_READONLY (loongarch_builtin_decls[i]) =1;
+ loongarch_get_builtin_decl_index[d->icode]=i;
+
}
/* Implement TARGET_BUILTIN_DECL. */
@@ -282,6 +388,42 @@ loongarch_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED)
return loongarch_builtin_decls[code];
}
+tree
+loongarch_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
+ tree *args, bool ignore ATTRIBUTE_UNUSED)
+{
+ if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
+ {
+ enum loongarch_function_type fn_code
+ = (enum loongarch_function_type) DECL_MD_FUNCTION_CODE (fndecl);
+ switch (fn_code)
+ {
+ case LARCH_BUILTIN_NANQ:
+ case LARCH_BUILTIN_NANSQ:
+ {
+ tree type = TREE_TYPE (TREE_TYPE (fndecl));
+ const char *str = c_getstr (*args);
+ int quiet = fn_code == LARCH_BUILTIN_NANQ;
+ REAL_VALUE_TYPE real;
+
+ if (str && real_nan (&real, str, quiet, TYPE_MODE (type)))
+ return build_real (type, real);
+ return NULL_TREE;
+ }
+
+ default:
+ break;
+ }
+ }
+
+#ifdef SUBTARGET_FOLD_BUILTIN
+ return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore);
+#endif
+
+ return NULL_TREE;
+}
+
+
/* Take argument ARGNO from EXP's argument list and convert it into
an expand operand. Store the operand in *OP. */
@@ -362,11 +504,33 @@ loongarch_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
switch (d->builtin_type)
{
case LARCH_BUILTIN_DIRECT:
+ case LARCH_BUILTIN_FCQ_DIRECT:
return loongarch_expand_builtin_direct (d->icode, target, exp, true);
case LARCH_BUILTIN_DIRECT_NO_TARGET:
return loongarch_expand_builtin_direct (d->icode, target, exp, false);
- }
+
+ case LARCH_BUILTIN_NNQ_DIRECT:
+ return expand_call ( exp ,target , ignore);
+
+ case LARCH_BUILTIN_HIQ_DIRECT:
+ {
+ machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
+ REAL_VALUE_TYPE inf;
+ rtx tmp;
+
+ real_inf (&inf);
+ tmp = const_double_from_real_value (inf, target_mode);
+
+ tmp=validize_mem (force_const_mem (target_mode,tmp));
+
+ if (target ==0)
+ target =gen_reg_rtx (target_mode);
+ emit_move_insn (target,tmp);
+
+ return target;
+ }
+ }
gcc_unreachable ();
}
@@ -175,11 +175,13 @@ extern void loongarch_register_frame_header_opt (void);
/* Routines implemented in loongarch-c.c. */
void loongarch_cpu_cpp_builtins (cpp_reader *);
+extern tree loongarch_fold_builtin (tree, int, tree*, bool);
extern void loongarch_init_builtins (void);
extern void loongarch_atomic_assign_expand_fenv (tree *, tree *, tree *);
extern tree loongarch_builtin_decl (unsigned int, bool);
extern rtx loongarch_expand_builtin (tree, rtx, rtx subtarget ATTRIBUTE_UNUSED,
machine_mode, int);
extern tree loongarch_build_builtin_va_list (void);
+extern machine_mode loongarch_c_mode_for_suffix (char suffix);
#endif /* ! GCC_LOONGARCH_PROTOS_H */
@@ -6790,6 +6790,16 @@ loongarch_set_handled_components (sbitmap components)
cfun->machine->reg_is_wrapped_separately[regno] = true;
}
+/* Target hook for c_mode_for_suffix. */
+machine_mode
+loongarch_c_mode_for_suffix (char suffix)
+{
+ if (suffix == 'q')
+ return TFmode;
+
+ return VOIDmode;
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -6901,6 +6911,10 @@ loongarch_set_handled_components (sbitmap components)
#define TARGET_BUILTIN_DECL loongarch_builtin_decl
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN loongarch_expand_builtin
+#undef TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN loongarch_fold_builtin
+#undef TARGET_C_MODE_FOR_SUFFIX
+#define TARGET_C_MODE_FOR_SUFFIX loongarch_c_mode_for_suffix
/* The generic ELF target does not always have TLS support. */
#ifdef HAVE_AS_TLS
@@ -44,6 +44,13 @@ (define_c_enum "unspec" [
UNSPEC_FSCALEB
UNSPEC_FLOGB
+ UNSPEC_INFQ
+ UNSPEC_HUGE_VALQ
+ UNSPEC_FABSQ
+ UNSPEC_COPYSIGNQ
+ UNSPEC_NANQ
+ UNSPEC_NANSQ
+
;; Override return address for exception handling.
UNSPEC_EH_RETURN
@@ -563,6 +570,15 @@ (define_int_attr bytepick_imm [(8 "1")
(48 "6")
(56 "7")])
+;; mathq function
+(define_int_iterator MATHQ[UNSPEC_INFQ UNSPEC_HUGE_VALQ
+ UNSPEC_NANQ UNSPEC_NANSQ])
+(define_int_attr mathq_pattern[(UNSPEC_INFQ "infq")
+ (UNSPEC_HUGE_VALQ "huge_valq")
+ (UNSPEC_NANQ "nanq")
+ (UNSPEC_NANSQ "nansq")]
+)
+
;;
;; ....................
;;
@@ -2008,6 +2024,59 @@ (define_insn "movfcc"
""
"movgr2cf\t%0,$r0")
+;; Implements functions with a "q" suffix
+
+(define_insn "<mathq_pattern>"
+ [(unspec:SI[(const_int 0)] MATHQ)]
+ ""
+ "")
+
+;;Implement __builtin_fabsq function.
+
+(define_insn_and_split "fabsq"
+ [(set (match_operand:TF 0 "register_operand" "=r")
+ (unspec:TF[(match_operand:TF 1 "register_operand" "rG")]
+ UNSPEC_FABSQ))]
+ ""
+ "#"
+ "reload_completed"
+[(set (zero_extract:DI (match_operand:DI 0 "register_operand")
+ (match_operand:SI 3 "const_int_operand")
+ (match_operand:SI 4 "const_int_operand"))
+ (match_operand:DI 2 "const_int_operand"))]
+{
+ operands[0] = gen_rtx_REG (Pmode, REGNO (operands[0])+1);
+ operands[2] = GEN_INT (0);
+ operands[3] = GEN_INT (1);
+ operands[4] = GEN_INT (63);
+}
+)
+
+;;Implement __builtin_copysignq function.
+
+(define_insn_and_split "copysignq"
+ [(set (match_operand:TF 0 "register_operand" "=r")
+ (unspec:TF[(match_operand:TF 1 "register_operand" "rG")
+ (match_operand:TF 2 "register_operand" "rG")]
+ UNSPEC_COPYSIGNQ))]
+ ""
+ "#"
+ "reload_completed"
+ [(set (match_operand:DI 2 "register_operand")
+ (lshiftrt :DI (match_operand:DI 2 "register_operand")
+ (match_operand:SI 4 "arith_operand")))
+ (set (zero_extract:DI (match_operand:DI 0 "register_operand")
+ (match_operand:SI 3 "const_int_operand")
+ (match_operand:SI 4 "const_int_operand"))
+ (match_operand:DI 2 "register_operand"))]
+{
+ operands[0] = gen_rtx_REG (Pmode,REGNO (operands[0])+1);
+ operands[2] = gen_rtx_REG (Pmode,REGNO (operands[2])+1);
+ operands[3] = GEN_INT (1);
+ operands[4] = GEN_INT (63);
+}
+)
+
;; Conditional move instructions.
(define_insn "*sel<code><GPR:mode>_using_<GPR2:mode>"
@@ -1,3 +1,6 @@
softfp_float_modes += tf
softfp_extensions += sftf dftf
softfp_truncations += tfsf tfdf
+#Used to implement a special 128-bit function with a q suffix
+LIB2ADD += $(srcdir)/config/loongarch/tf-signs.c
+
new file mode 100644
@@ -0,0 +1,59 @@
+/* Copyright (C) 2008-2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC 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 General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+union _FP_UNION_Q
+{
+ __float128 flt;
+ struct
+ {
+ unsigned long frac0 : 64;
+ unsigned long frac1 : 48;
+ unsigned exp : 15;
+ unsigned sign : 1;
+ } bits __attribute__((packed));
+};
+
+__float128 __nanq (const char *str);
+__float128 __nansq (const char *str);
+
+__float128 __nanq (const char * str)
+{
+ union _FP_UNION_Q nan;
+ nan.bits.frac0 = 0;
+ nan.bits.frac1 = 0;
+ nan.bits.exp = 0x7FFF;
+ nan.bits.sign = 0;
+
+ return nan.flt;
+}
+__float128 __nansq (const char *str)
+{
+ union _FP_UNION_Q nan;
+ nan.bits.frac0 = 0xFFFFFFFFFFFFFFFFUL;
+ nan.bits.frac1 = 0x0000FFFFFFFFFFFFUL;
+ nan.bits.exp = 0x7FFF;
+ nan.bits.sign = 0;
+
+ return nan.flt;
+}
+