@@ -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 ();
}
@@ -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 */
@@ -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
@@ -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>"
@@ -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
+
new file mode 100644
@@ -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;
+}
+