From: Xiaolong Chen <chenxiaol...@loongson.cn> 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}.
gcc/ChangeLog: * config/loongarch/loongarch-builtins.cc (DEF_LARCH_FTYPE): (MATHQ_NUMS=):Add the type of the builtin(q) function. (enum loongarch_builtin_type):Add the type of the function. (FLOAT_BUILTIN_HUGE): (FLOAT_BUILTIN_INFQ): (FLOAT_BUILTIN_FABSQ): (FLOAT_BUILTIN_COPYSIGNQ): (FLOAT_BUILTIN_NANQ): (FLOAT_BUILTIN_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): (<mathq_pattern>):Add an instruction template to the machine description file to generate information such as the icode used by the function and the constructor. libgcc/ChangeLog: * config/loongarch/t-softfp-tf: * config/loongarch/tf-signs.c: New file. --- gcc/config/loongarch/loongarch-builtins.cc | 196 ++++++++++++++++++++- gcc/config/loongarch/loongarch-protos.h | 2 + gcc/config/loongarch/loongarch.cc | 14 ++ gcc/config/loongarch/loongarch.md | 25 +++ libgcc/config/loongarch/t-softfp-tf | 3 + libgcc/config/loongarch/tf-signs.c | 99 +++++++++++ 6 files changed, 337 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..cb7f0e60674 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 */ +static 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 { @@ -62,7 +73,25 @@ enum loongarch_builtin_type /* The function corresponds directly to an .md pattern. There is no return value and the arguments are mapped to operands 0 and above. */ LARCH_BUILTIN_DIRECT_NO_TARGET, + + /*The function corresponds to an __builtin_huge_valq */ + LARCH_BUILTIN_HUGE_DIRECT , + + /*Define the type of the __builtin_infq function */ + LARCH_BUILTIN_INFQ_DIRECT , + + /*Define the type of the __builtin_fabsq function*/ + LARCH_BUILTIN_FABSQ_DIRECT , + /*Define the type of the __builtin_copysignq function */ + LARCH_BUILTIN_COPYSIGNQ_DIRECT , + + + /*Define the type of the __builtin_copysignq function */ + LARCH_BUILTIN_NANQ_DIRECT , + + /*Define the type of the __builtin_copysignq function */ + LARCH_BUILTIN_NANSQ_DIRECT , }; /* Declare an availability predicate for built-in functions that require @@ -135,6 +164,41 @@ AVAIL_ALL (hard_float, TARGET_HARD_FLOAT_ABI) #define DIRECT_NO_TARGET_BUILTIN(INSN, FUNCTION_TYPE, AVAIL) \ LARCH_BUILTIN (INSN, #INSN, LARCH_BUILTIN_DIRECT_NO_TARGET, \ FUNCTION_TYPE, AVAIL) +/* Define an float to do funciton huge_valq*/ +#define FLOAT_BUILTIN_HUGE(INSN, FUNCTION_TYPE) \ + { CODE_FOR_ ## INSN, \ + "__builtin_" #INSN, LARCH_BUILTIN_HUGE_DIRECT, \ + FUNCTION_TYPE, loongarch_builtin_avail_default } + +/* Define an float to do funciton infq*/ +#define FLOAT_BUILTIN_INFQ(INSN, FUNCTION_TYPE) \ + { CODE_FOR_ ## INSN, \ + "__builtin_" #INSN, LARCH_BUILTIN_INFQ_DIRECT, \ + FUNCTION_TYPE, loongarch_builtin_avail_default } + +/* Define an float to do funciton fabsq*/ +#define FLOAT_BUILTIN_FABSQ(INSN, FUNCTION_TYPE) \ + { CODE_FOR_ ## INSN, \ + "__builtin_" #INSN, LARCH_BUILTIN_FABSQ_DIRECT, \ + FUNCTION_TYPE, loongarch_builtin_avail_default } + +/* Define an float to do funciton copysignq*/ +#define FLOAT_BUILTIN_COPYSIGNQ(INSN, FUNCTION_TYPE) \ + { CODE_FOR_ ## INSN, \ + "__builtin_" #INSN, LARCH_BUILTIN_COPYSIGNQ_DIRECT, \ + FUNCTION_TYPE, loongarch_builtin_avail_default } + +/* Define an float to do funciton nanq*/ +#define FLOAT_BUILTIN_NANQ(INSN, FUNCTION_TYPE) \ + { CODE_FOR_ ## INSN, \ + "__builtin_" #INSN, LARCH_BUILTIN_NANQ_DIRECT, \ + FUNCTION_TYPE, loongarch_builtin_avail_default } + +/* Define an float to do funciton nansq*/ +#define FLOAT_BUILTIN_NANSQ(INSN, FUNCTION_TYPE) \ + { CODE_FOR_ ## INSN, \ + "__builtin_" #INSN, LARCH_BUILTIN_NANSQ_DIRECT, \ + FUNCTION_TYPE, loongarch_builtin_avail_default } static const struct loongarch_builtin_description loongarch_builtins[] = { #define LARCH_MOVFCSR2GR 0 @@ -183,6 +247,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_HUGE (huge_valq, LARCH_BUILTIN_HUGE_VALQ), + FLOAT_BUILTIN_INFQ (infq, LARCH_BUILTIN_INFQ), + FLOAT_BUILTIN_FABSQ (fabsq, LARCH_BUILTIN_FABSQ), + FLOAT_BUILTIN_NANQ (nanq, LARCH_BUILTIN_NANQ), + FLOAT_BUILTIN_NANSQ (nansq, LARCH_BUILTIN_NANSQ), + FLOAT_BUILTIN_COPYSIGNQ (copysignq, LARCH_BUILTIN_COPYSIGNQ), + }; /* Index I is the function declaration for loongarch_builtins[I], or null if @@ -254,11 +326,13 @@ loongarch_init_builtins (void) { const struct loongarch_builtin_description *d; unsigned int i; - tree type; + tree type,ftype; + 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 +344,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"); + + ftype = build_function_type_list (long_double_type_node,NULL_TREE); + d = &loongarch_builtins[i]; + loongarch_builtin_decls[i] + =add_builtin_function("__builtin_huge_valq",ftype, + i,BUILT_IN_MD,NULL,NULL_TREE); + loongarch_get_builtin_decl_index[d->icode]=i++; + + + ftype = build_function_type_list (long_double_type_node,NULL_TREE); + d = &loongarch_builtins[i]; + loongarch_builtin_decls[i] + =add_builtin_function("__builtin_infq",ftype, + i,BUILT_IN_MD,NULL,NULL_TREE); + loongarch_get_builtin_decl_index[d->icode]=i++; + + ftype = 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",ftype, + i,BUILT_IN_MD,"__fabstf2",NULL_TREE); + TREE_READONLY (loongarch_builtin_decls[i]) =1; + loongarch_get_builtin_decl_index[d->icode]=i++; + + ftype = 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",ftype, + i,BUILT_IN_MD,"__copysigntf3",NULL_TREE); + TREE_READONLY (loongarch_builtin_decls[i]) =1; + loongarch_get_builtin_decl_index[d->icode]=i++; + + ftype=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",ftype, + 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",ftype, + 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 +413,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. */ @@ -366,7 +533,32 @@ loongarch_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, case LARCH_BUILTIN_DIRECT_NO_TARGET: return loongarch_expand_builtin_direct (d->icode, target, exp, false); + + case LARCH_BUILTIN_NANQ_DIRECT: + case LARCH_BUILTIN_NANSQ_DIRECT: + case LARCH_BUILTIN_FABSQ_DIRECT: + case LARCH_BUILTIN_COPYSIGNQ_DIRECT: + return expand_call ( exp ,target , ignore); + + case LARCH_BUILTIN_HUGE_DIRECT: + case LARCH_BUILTIN_INFQ_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..6fa0d10f20c 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 5b8b93eb24b..0da147358b1 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -6789,6 +6789,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" @@ -6900,6 +6910,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..d7a5922f33d 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -43,6 +43,13 @@ (define_c_enum "unspec" [ UNSPEC_FTINTRP 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,17 @@ (define_int_attr bytepick_imm [(8 "1") (48 "6") (56 "7")]) +;; mathq function +(define_int_iterator MATHQ [UNSPEC_INFQ UNSPEC_HUGE_VALQ UNSPEC_FABSQ UNSPEC_COPYSIGNQ + UNSPEC_NANQ UNSPEC_NANSQ]) +(define_int_attr mathq_pattern [(UNSPEC_INFQ "infq") + (UNSPEC_HUGE_VALQ "huge_valq") + (UNSPEC_FABSQ "fabsq") + (UNSPEC_COPYSIGNQ "copysignq") + (UNSPEC_NANQ "nanq") + (UNSPEC_NANSQ "nansq")] +) + ;; ;; .................... ;; @@ -2008,6 +2026,13 @@ (define_insn "movfcc" "" "movgr2cf\t%0,$r0") +;; Implements functions with a "q" suffix + +(define_insn "<mathq_pattern>" + [(unspec:SI [(const_int 0)]MATHQ)] + "" + " ") + ;; 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..5ba0c8dea65 --- /dev/null +++ b/libgcc/config/loongarch/tf-signs.c @@ -0,0 +1,99 @@ +/* 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/>. */ +#include<stddef.h> +#include<string.h> + +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 __copysigntf3 (__float128, __float128); +__float128 __fabstf2 (__float128); +int __signbittf2 (__float128); +__float128 nanq(const char *str); +__float128 nansq(const char *str); + +__float128 +__copysigntf3 (__float128 a, __float128 b) +{ + union _FP_UNION_Q A, B; + + A.flt = a; + B.flt = b; + A.bits.sign = B.bits.sign; + + return A.flt; +} + +__float128 +__fabstf2 (__float128 a) +{ + union _FP_UNION_Q A; + + A.flt = a; + A.bits.sign = 0; + + return A.flt; +} + +int +__signbittf2 (__float128 a) +{ + union _FP_UNION_Q A; + + A.flt = a; + + return A.bits.sign; +} + +__float128 nanq(const char * str) +{ + union _FP_UNION_Q nan; + nan.bits.frac0 = 0; + nan.bits.frac1 = 0; + nan.bits.exp = 0x7FFF; // Exponent field set to all 1's for NaN + nan.bits.sign = 1; // Set the quiet NaN flag to 1 + if(str!=NULL && strlen(str)>0) + return nan.flt; + return 0; +} +__float128 nansq(const char *str) +{ + union _FP_UNION_Q nan; + nan.bits.frac0 = 0; + nan.bits.frac1 = 0; + nan.bits.exp = 0x7FFF; // Exponent field set to all 1's for NaN + nan.bits.sign = 1; // Set the quiet NaN flag to 1 + if(str!=NULL && strlen(str)>0) + return nan.flt; +return 0; +} + -- 2.20.1