[v2] LoongArch:Implement 128-bit floating point functions in gcc.

Message ID 20230808020902.11626-1-chenxiaolong@loongson.cn
State Accepted
Headers
Series [v2] LoongArch:Implement 128-bit floating point functions in gcc. |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

chenxiaolong Aug. 8, 2023, 2:09 a.m. UTC
  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=):Counts the number of builtin functions with the
        suffix "q".
	(enum loongarch_builtin_type):Add the type of the function.
	(FLOAT_BUILTIN_HIQ):
	(FLOAT_BUILTIN_NNFCQ):
	(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 | 158 ++++++++++++++++++++-
 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, 299 insertions(+), 2 deletions(-)
 create mode 100644 libgcc/config/loongarch/tf-signs.c
  

Comments

Xi Ruoyao Aug. 8, 2023, 2:24 a.m. UTC | #1
On Tue, 2023-08-08 at 10:09 +0800, chenxiaolong wrote:
> +/* Count the number of functions with "q" as the suffix.  */
> +const int MATHQ_NUMS=(int)LARCH_MAX_FTYPE_MAX-(int)LARCH_BUILTIN_HUGE_VALQ;

Format issue still not fixed.

> +__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 = 1;
> +  if (str  !=  NULL && strlen (str) > 0)
> +      return nan.flt;
> +  return 0;
> +}

I don't think the logic is correct.  __builtin_nanq("") should return a
NaN, not 0.

> +  if (str  !=  NULL && strlen (str) > 0)
> +      return nan.flt;

Indent is 2, not 4.

And we don't need to check "str != NULL" here.  Calling nan()-family
functions with a null tagp is deemed undefined behavior.

> +__float128 nansq (const char *str)
> +{
> +  union _FP_UNION_Q nan;
> +  nan.bits.frac0 = 0;
> +  nan.bits.frac1 = 0;
> +  nan.bits.exp = 0x7FFF;
> +  nan.bits.sign = 1;
> +  if (str != NULL && strlen (str) > 0)
> +      return nan.flt;
> +  return 0;
> +}

Same logic error.  And this seems exactly same as nanq, the analogous is
definitely wrong because __builtin_nanq should return a quiet NaN, but
__builtin_nansq should return a signaling NaN.
  
Xi Ruoyao Aug. 8, 2023, 2:37 a.m. UTC | #2
On Tue, 2023-08-08 at 10:24 +0800, Xi Ruoyao wrote:

And I think this way to implement these functions (using libgcc calls)
is not the best.

On 64-bit LoongArch a __float128 is stored in a pair of GPR, so
operations like copysignq and absq can be implemented much more
efficiently by expanding them using bstrins and bstrpick instructions in
the compiler.  For example:

__float128 
absq (__float128 val)
{
  return __builtin_absq (val);
}

should be compiled to:

bstrins.d $a1, $zero, 63, 63
jr $ra

Instead of

b __fabstf2

(perhaps, unless -Os).

> > +__float128 nanq        (const char * str)

Using "nanq" as the symbol name is unacceptable as well.  Use "__nanq"
or something.  "nanq" is not reserved for implementation, so it may
cause a conflict in the future if "nanq" finally become a standard
function or the users defines their own "nanq" function.
>
  
chenxiaolong Aug. 8, 2023, 7:14 a.m. UTC | #3
Ok, thanks for the advice. I have modified __builtin_nanq("") and __builtin_nansq("") in gcc according to the functionality of the function, and the implementation is shown in the following code.

>>>
__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;
}

-----

> -----原始邮件-----
> 发件人: "Xi Ruoyao" <xry111@xry111.site>
> 发送时间:2023-08-08 10:24:39 (星期二)
> 收件人: chenxiaolong <chenxiaolong@loongson.cn>, gcc-patches@gcc.gnu.org
> 抄送: i@xen0n.name, xuchenghua@loongson.cn, chenglulu@loongson.cn
> 主题: Re: [PATCH v2] 	LoongArch:Implement 128-bit floating point functions in gcc.
> 
> On Tue, 2023-08-08 at 10:09 +0800, chenxiaolong wrote:
> > +/* Count the number of functions with "q" as the suffix.  */
> > +const int MATHQ_NUMS=(int)LARCH_MAX_FTYPE_MAX-(int)LARCH_BUILTIN_HUGE_VALQ;
> 
> Format issue still not fixed.
> 
> > +__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 = 1;
> > +  if (str  !=  NULL && strlen (str) > 0)
> > +      return nan.flt;
> > +  return 0;
> > +}
> 
> I don't think the logic is correct.  __builtin_nanq("") should return a
> NaN, not 0.
> 
> > +  if (str  !=  NULL && strlen (str) > 0)
> > +      return nan.flt;
> 
> Indent is 2, not 4.
> 
> And we don't need to check "str != NULL" here.  Calling nan()-family
> functions with a null tagp is deemed undefined behavior.
> 
> > +__float128 nansq (const char *str)
> > +{
> > +  union _FP_UNION_Q nan;
> > +  nan.bits.frac0 = 0;
> > +  nan.bits.frac1 = 0;
> > +  nan.bits.exp = 0x7FFF;
> > +  nan.bits.sign = 1;
> > +  if (str != NULL && strlen (str) > 0)
> > +      return nan.flt;
> > +  return 0;
> > +}
> 
> Same logic error.  And this seems exactly same as nanq, the analogous is
> definitely wrong because __builtin_nanq should return a quiet NaN, but
> __builtin_nansq should return a signaling NaN.
> 
> -- 
> Xi Ruoyao <xry111@xry111.site>
> School of Aerospace Science and Technology, Xidian University


本邮件及其附件含有龙芯中科的商业秘密信息,仅限于发送给上面地址中列出的个人或群组。禁止任何其他人以任何形式使用(包括但不限于全部或部分地泄露、复制或散发)本邮件及其附件中的信息。如果您错收本邮件,请您立即电话或邮件通知发件人并删除本邮件。 
This email and its attachments contain confidential information from Loongson Technology , which is intended only for the person or entity whose address is listed above. Any use of the information contained herein in any way (including, but not limited to, total or partial disclosure, reproduction or dissemination) by persons other than the intended recipient(s) is prohibited. If you receive this email in error, please notify the sender by phone or email immediately and delete it.
  

Patch

diff --git a/gcc/config/loongarch/loongarch-builtins.cc b/gcc/config/loongarch/loongarch-builtins.cc
index b929f224dfa..6e32f86fc52 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,12 @@  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,
+
+  /* Define the type of the __builtin_{nanq,nansq,fabsq,copysignq} function.  */
+  LARCH_BUILTIN_NNFCQ_DIRECT
+
 };
 
 /* Declare an availability predicate for built-in functions that require
@@ -136,6 +153,18 @@  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 {nanq,nansq,fabsq,copysignq}.*/
+#define FLOAT_BUILTIN_NNFCQ(INSN, FUNCTION_TYPE)      \
+    { CODE_FOR_ ## INSN,				\
+    "__builtin_" #INSN,  LARCH_BUILTIN_NNFCQ_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 +212,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_NNFCQ (fabsq, LARCH_BUILTIN_FABSQ),
+  FLOAT_BUILTIN_NNFCQ (nanq, LARCH_BUILTIN_NANQ),
+  FLOAT_BUILTIN_NNFCQ (nansq, LARCH_BUILTIN_NANSQ),
+  FLOAT_BUILTIN_NNFCQ (copysignq, LARCH_BUILTIN_COPYSIGNQ),
+
 };
 
 /* Index I is the function declaration for loongarch_builtins[I], or null if
@@ -255,10 +292,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 +310,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,  "__fabstf2",  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,  "__copysigntf3",  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 +379,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 +499,28 @@  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_NNFCQ_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 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..c545386aa7b 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,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..395d6a18623
--- /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;
+  nan.bits.sign = 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;
+  nan.bits.sign = 1;
+  if (str != NULL && strlen (str) > 0)
+      return nan.flt;
+  return 0;
+}
+