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; +} + -- 2.20.1