diff mbox series

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

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

Commit Message

chenxiaolong Aug. 8, 2023, 2:13 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
diff mbox series

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