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

Reply via email to