From dac9d6118049e1be36517d2361bbfadad5c73680 Mon Sep 17 00:00:00 2001 From: Petter Tomner Date: Sat, 16 Oct 2021 21:55:20 +0200 Subject: [PATCH 2/2] long long Add long long, long double and complex long double constants This patch adds entrypoints to make constants (literals) for long long, long double and complex long double types. Also, it fixes problems with all floating point numbers in write_reproducer. I.e. support NAN and INF values, aswell as proper precision for double and long double. Which is needed for testing this patch. Signed-off-by: 2021-10-21 Petter Tomner gcc/jit/ * jit-playback.c : (new_rvalue_from_const ): New (new_rvalue_from_const ): Uses long long instead (new_rvalue_from_const ): New (new_rvalue_from_const <_Complex long double>) : New * jit-recording.c : (dump_reproducer_to_file) : Type punning NANs (reproducer_write_arr) : arr -> "char array literal"-string (memento_of_new_rvalue_from_const ) : New (memento_of_new_rvalue_from_const ) : New (memento_of_new_rvalue_from_const <_Complex long double>) : New (memento_of_new_rvalue_from_const ::make_debug_string): %g instead of %f (memento_of_new_rvalue_from_const ::write_reproducer): %a instead of %f, handle NAN and INF (memento_of_new_rvalue_from_const <_Complex double>::write_reproducer): %a instead of %f, handle NAN and INF. Use CMPLX macro. * libgccjit.c : * libgccjit.h : (LIBGCCJIT_HAVE_LONGLONG_CONSTANTS) : New (gcc_jit_context_new_rvalue_from_long_long) : New (gcc_jit_context_new_rvalue_from_long_double) : New (gcc_jit_context_new_rvalue_from_complex_long_double) : New * libgccjit++.h : New entrypoints * libgccjit.map: New entrypoints added to ABI 26 gcc/testsuite/ * jit.dg/all-non-failing-tests.h: Added test-long-literals.c * jit.dg/test-long-literals.c: New gcc/jit/docs/topics/ * compatibility.rst : Updated docs * expressions.rst --- gcc/jit/docs/topics/compatibility.rst | 6 +- gcc/jit/docs/topics/expressions.rst | 48 +- gcc/jit/jit-playback.cc | 144 +++++- gcc/jit/jit-recording.cc | 442 ++++++++++++++++++- gcc/jit/libgccjit++.h | 39 ++ gcc/jit/libgccjit.cc | 46 ++ gcc/jit/libgccjit.h | 33 +- gcc/jit/libgccjit.map | 4 + gcc/testsuite/jit.dg/all-non-failing-tests.h | 7 + gcc/testsuite/jit.dg/test-long-literals.c | 283 ++++++++++++ 10 files changed, 1028 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-long-literals.c diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 6922a2f67e9..e8b16926330 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -384,13 +384,15 @@ alignment of a variable: ``LIBGCCJIT_ABI_26`` -------------------- ``LIBGCCJIT_ABI_26`` covers the addition of support for complex types, -literals for complex types as well as the +literals for long long, long double and complex types as well as the complex binary operator. Note that :c:macro:`GCC_JIT_TYPE_COMPLEX_FLOAT` etc. existed in earlier ABI:s, but were not functional. * :func:`gcc_jit_context_new_rvalue_from_complex_double` + * :func:`gcc_jit_context_new_rvalue_from_complex_long_double` + * :func:`gcc_jit_context_new_rvalue_from_long_double` + * :func:`gcc_jit_context_new_rvalue_from_long_long` * :func:`gcc_jit_context_set_bool_enable_complex_types` * :c:macro:`GCC_JIT_BINARY_OP_COMPLEX` - diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 2af19dcbe28..c589e684856 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -70,6 +70,21 @@ Simple expressions Given a numeric type (integer or floating point), build an rvalue for the given constant :expr:`long` value. +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_long_long (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type, \ + long long value) + + Given a numeric type (integer or floating point), build an rvalue for + the given constant :expr:`long long` value. + + This function was added asd in :ref:`LIBGCCJIT_ABI_26`; + you can test for its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS + .. function:: gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \ gcc_jit_type *numeric_type) @@ -98,6 +113,21 @@ Simple expressions Given a numeric type (integer or floating point), build an rvalue for the given constant :expr:`double` value. +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_long_double (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type, \ + long double value) + + Given a floating point type, build an rvalue for + the given constant :expr:`long double`. + + This function was added in :ref:`LIBGCCJIT_ABI_26`; + you can test for its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS + .. function:: gcc_jit_rvalue *\ gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, \ gcc_jit_type *numeric_type, \ @@ -114,6 +144,22 @@ Simple expressions #ifdef LIBGCCJIT_HAVE_COMPLEX +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_complex_long_double (gcc_jit_context *ctxt,\ + gcc_jit_type *numeric_type,\ + _Complex long double value); + + Given a floating point type, build an rvalue for + the given constant :expr:`_Complex long double`. When the result type is + non-complex, the imaginary part is discarded. + + This function was added in :ref:`LIBGCCJIT_ABI_26`; + you can test for its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS + .. function:: gcc_jit_rvalue *\ gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \ gcc_jit_type *pointer_type, \ @@ -558,7 +604,7 @@ Binary Operation C equivalent Supported operand type the imaginary. Negative zeroes are preserved and Inf:s do not lead to NaNs. - This operator was added in LIBGCCJIT_ABI_26; + This operator was added in :ref:`LIBGCCJIT_ABI_26`; you can test for its presence using .. code-block:: c diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 49ea10fd1cb..f97404730bd 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see . */ #include "config.h" +#include #define INCLUDE_MUTEX #include "system.h" #include "coretypes.h" @@ -60,6 +61,13 @@ along with GCC; see the file COPYING3. If not see #define SET_DECL_JIT_BIT_FIELD(NODE) \ (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1) +/* "There are always [atleast] 32 bits in each long, no matter the + size of the hosts long. We handle floating point representations + with up to 192 bits", says native_interpret_real() in fold-const.c. + + A define for the amount of these longs needed per long double. */ +#define N_LONGS_LDOUBLE (sizeof (long double) / sizeof (uint32_t) + ((sizeof (long double) % sizeof (uint32_t)) ? 1 : 0)) + /* gcc::jit::playback::context::build_cast uses the convert.h API, which in turn requires the frontend to provide a "convert" function, apparently as a fallback for casts that can be simplified @@ -937,15 +945,14 @@ new_rvalue_from_const (type *type, } } -/* Specialization of making an rvalue from a const, for host . */ +/* Specialization of making an rvalue from a const, for host . */ template <> rvalue * context:: -new_rvalue_from_const (type *type, - long value) +new_rvalue_from_const (type *type, + long long value) { - // FIXME: type-checking, or coercion? tree inner_type = type->as_tree (); if (INTEGRAL_TYPE_P (inner_type)) { @@ -980,6 +987,17 @@ new_rvalue_from_const (type *type, } } +/* Specialization of making an rvalue from a const, for host . */ + +template <> +rvalue * +context:: +new_rvalue_from_const (type *type, + long value) +{ + return new_rvalue_from_const (type, value); +} + /* Specialization of making an rvalue from a const, for host . */ template <> @@ -1041,6 +1059,65 @@ new_rvalue_from_const (type *type, } } +/* Specialization of making an rvalue from a const, for host . */ + +template <> +rvalue * +context:: +new_rvalue_from_const (type *type, + long double value) +{ + tree inner_type = type->as_tree (); + + scalar_float_mode mode = SCALAR_FLOAT_TYPE_MODE (long_double_type_node); + + union + { + long double as_long_double; + uint32_t as_uint32s[N_LONGS_LDOUBLE]; + } u_real, u_imag; + + u_real.as_long_double = value; + + long int as_long_ints[N_LONGS_LDOUBLE]; + + for (unsigned i = 0; i < N_LONGS_LDOUBLE; i++) + as_long_ints[i] = u_real.as_uint32s[i]; + + REAL_VALUE_TYPE real_value; + real_from_target (&real_value, as_long_ints, mode); + + if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + + REAL_VALUE_TYPE imag_value; + + long int zero_as_long_ints[N_LONGS_LDOUBLE]; + u_imag.as_long_double = 0.; + + for (unsigned i = 0; i < N_LONGS_LDOUBLE; i++) + zero_as_long_ints[i] = u_imag.as_uint32s[i]; + + real_from_target (&imag_value, zero_as_long_ints, mode); + + real_type = complex_real_to_real (inner_type); + + tree_real = build_real (real_type, real_value); + tree_imag = build_real (real_type, imag_value); + + tree inner = build_complex (inner_type, tree_real, tree_imag); + return new rvalue (this, inner); + } + else + { + tree inner = build_real (inner_type, real_value); + return new rvalue (this, inner); + } +} + /* Specialization of making an rvalue from a const, for host . */ @@ -1096,6 +1173,65 @@ new_rvalue_from_const <_Complex double> (type *type, } } +/* Specialization of making an rvalue from a const, + for host <_Complex long double>. */ + +template <> +rvalue * +context:: +new_rvalue_from_const <_Complex long double> (type *type, + _Complex long double value) +{ + tree inner_type = type->as_tree (); + + scalar_float_mode mode = SCALAR_FLOAT_TYPE_MODE (long_double_type_node); + + union + { + long double as_long_double; + uint32_t as_uint32s[N_LONGS_LDOUBLE]; + } u_real, u_imag; + + u_real.as_long_double = creall(value); + long int as_long_ints[N_LONGS_LDOUBLE]; + + for (unsigned i = 0; i < N_LONGS_LDOUBLE; i++) + as_long_ints[i] = u_real.as_uint32s[i]; + + REAL_VALUE_TYPE real_value; + real_from_target (&real_value, as_long_ints, mode); + + if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + + REAL_VALUE_TYPE imag_value; + + long int value_as_long_ints[N_LONGS_LDOUBLE]; + u_imag.as_long_double = cimagl(value); + + for (unsigned i = 0; i < N_LONGS_LDOUBLE; i++) + value_as_long_ints[i] = u_imag.as_uint32s[i]; + + real_from_target (&imag_value, value_as_long_ints, mode); + + real_type = complex_real_to_real (inner_type); + + tree_real = build_real (real_type, real_value); + tree_imag = build_real (real_type, imag_value); + + tree inner = build_complex (inner_type, tree_real, tree_imag); + return new rvalue (this, inner); + } + else + { + tree inner = build_real (inner_type, real_value); + return new rvalue (this, inner); + } +} + /* Specialization of making an rvalue from a const, for host . */ template <> diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index ed788502c15..baa75311b31 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include +#include #include "jit-builtins.h" #include "jit-recording.h" @@ -1836,8 +1837,48 @@ recording::context::dump_reproducer_to_file (const char *path) " gcc_jit_context_dump_reproducer_to_file.\n\n"); print_version (r.get_file (), " ", false); r.write ("*/\n"); - r.write ("#include \n\n"); - r.write ("#pragma GCC diagnostic ignored \"-Wunused-variable\"\n\n"); + r.write ( + "#include \n" + "#include \n" + "#include \n" + "#include \n\n"); + r.write ("#pragma GCC diagnostic ignored \"-Wunused-variable\"\n"); + r.write ("#pragma GCC diagnostic ignored \"-Wunused-function\"\n\n"); + /* Type punning unions */ + r.write ("union dull { double d; unsigned long long ull; };\n\n"); + r.write ( + "union ldarr { long double ld; unsigned arr[sizeof (long double)];};\n\n"); + + /* Functions for type punning nan:s, keeping bit representation */ + r.write ( + "/* Convert type punned uint 64 to double NaN.\n" + " Might lose/corrupt payload between architectures. */\n" + "static double\n" + "ull_to_d (unsigned long long ull)\n" + "{\n" + " union dull u; u.ull = ull;\n" + " /* Paranoia check for foreign NaN representation. */\n" + " if (!isnan (u.d)) return NAN;\n" + " return u.d;\n" + "}\n\n"); + r.write ( + "/* Convert array to long double NaN.\n" + " Might lose/corrupt payload between architectures. */\n" + "static long double\n" + "arr_to_ld (unsigned char *arr, int len)\n" + "{\n" + " union ldarr u;\n" + /* Since long double sizes can vary between architectures, + we need to handle that. */ + " /* For foreign long double sizes */\n" + " if (sizeof u.arr != len) return NAN;\n" + " memcpy (u.arr, arr, len);\n" + /* The size might fool us becouse of padding, so check it is a nan. */ + " /* Handle foreign representations that is not NaN on this machine. */\n" + " if (!isnan (u.ld)) return NAN;\n" + " return u.ld;\n" + "}\n\n"); + r.write ("static void\nset_options ("); r.write_params (contexts); r.write (");\n\n"); @@ -5125,8 +5166,11 @@ recording::global::write_reproducer (reproducer &r) /* Explicit specialization of the various mementos we're interested in. */ template class recording::memento_of_new_rvalue_from_const ; template class recording::memento_of_new_rvalue_from_const ; +template class recording::memento_of_new_rvalue_from_const ; template class recording::memento_of_new_rvalue_from_const ; +template class recording::memento_of_new_rvalue_from_const ; template class recording::memento_of_new_rvalue_from_const <_Complex double>; +template class recording::memento_of_new_rvalue_from_const <_Complex long double>; template class recording::memento_of_new_rvalue_from_const ; /* Implementation of the pure virtual hook recording::memento::replay_into @@ -5263,6 +5307,70 @@ recording::memento_of_new_rvalue_from_const ::write_reproducer (reproducer m_value); } +/* The make_debug_string specialization for , rendering it as + (TARGET_TYPE)LITERAL + e.g. + "(long long)42". */ + +template <> +string * +memento_of_new_rvalue_from_const ::make_debug_string () +{ + return string::from_printf (m_ctxt, + "(%s)%lli", + m_type->get_debug_string (), + m_value); +} + +/* The get_wide_int specialization for . */ + +template <> +bool +memento_of_new_rvalue_from_const ::get_wide_int (wide_int *out) const +{ + *out = wi::shwi (m_value, sizeof (m_value) * 8); + return true; +} + +/* The write_reproducer specialization for . */ + +template <> +void +recording::memento_of_new_rvalue_from_const :: +write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "rvalue"); + + /* Same special case as in long */ + if (m_value == LONG_LONG_MIN) + { + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_long_long (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " %lldLL - 1); /* long long value */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value + 1); + return; + } + + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_long_long (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " %lldLL); /* long long value */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value); +} + + + /* The make_debug_string specialization for , rendering it as (TARGET_TYPE)LITERAL e.g. @@ -5273,7 +5381,7 @@ string * memento_of_new_rvalue_from_const ::make_debug_string () { return string::from_printf (m_ctxt, - "(%s)%f", + "(%s)%g", m_type->get_debug_string (), m_value); } @@ -5287,6 +5395,18 @@ memento_of_new_rvalue_from_const ::get_wide_int (wide_int *) const return false; } +/* For typepruning NaNs. */ +union dull { + double d; + unsigned long long ull; +}; + +union ldarr { + long double ld; + unsigned char arr[sizeof(long double)]; +}; + + /* The write_reproducer specialization for . */ template <> @@ -5294,14 +5414,154 @@ void recording::memento_of_new_rvalue_from_const ::write_reproducer (reproducer &r) { const char *id = r.make_identifier (this, "rvalue"); - r.write (" gcc_jit_rvalue *%s =\n" - " gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n" - " %s, /* gcc_jit_type *numeric_type */\n" - " %f); /* double value */\n", - id, - r.get_identifier (get_context ()), - r.get_identifier_as_type (m_type), - m_value); + + if (std::isfinite (m_value)) + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %.9g */\n" + " %a);\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value, m_value); + else if (std::isinf (m_value)) + { + const char *sign = ""; + if (m_value < 0) + sign = "-"; + + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* inf */\n" + " %sINFINITY);\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + sign); + } + else if (std::isnan (m_value)) { + union dull u; + u.d = m_value; + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_double (%s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* NaN */\n" + " ull_to_d(%#llx));\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + u.ull); + + } +} + +/* The make_debug_string specialization for , rendering it as + (TARGET_TYPE)LITERAL + e.g. + "(float)42.0". */ + +template <> +string * +memento_of_new_rvalue_from_const ::make_debug_string () +{ + return string::from_printf (m_ctxt, + "(%s)%Lg", + m_type->get_debug_string (), + m_value); +} + +/* The get_wide_int specialization for . */ + +template <> +bool +memento_of_new_rvalue_from_const ::get_wide_int (wide_int *) const +{ + return false; +} + +/* Helper function for write_reproducer() + + Write an array of unsigned chars to the reproducer, like: + {0x12, 0x34, ... } */ +static void +reproducer_write_arr (reproducer &r, unsigned char *arr, int len) +{ + if (len == 0) + return; + + r.write ("{"); + for (int i = 0; i < len - 1; i++) + r.write ("%#x , ", arr[i]); + r.write ("%#x }", arr[len - 1]); +} + +/* The write_reproducer specialization for . */ + +template <> +void +recording::memento_of_new_rvalue_from_const :: +write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "rvalue"); + + if (std::isfinite (m_value)) + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_long_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %.9Lg */\n" + " %LaL); /* long double value */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value, m_value); + else if (std::isinf (m_value)) + { + const char *sign = ""; + if (m_value < 0) + sign = "-"; + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_long_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* inf */\n" + " %sINFINITY);\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + sign); + } + else + { + union ldarr u; /* For type punning to array */ + u.ld = m_value; + + r.write (" gcc_jit_rvalue *%s;\n", id); + /* Scope for local */ + r.write (" { /* long double NaN stored in char arr */\n"); + /* Write an char arr of the bytes of the NaN */ + r.write (" unsigned char arr[] = "); + reproducer_write_arr (r, u.arr, sizeof u.arr); + r.write (";\n"); + + r.write ( + " %s =\n" + " gcc_jit_context_new_rvalue_from_long_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %Lg */\n" + " arr_to_ld (arr, sizeof arr));\n", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + m_value); + + r.write (" }\n"); /* Close scope */ + } } /* The make_debug_string specialization for , rendering it as @@ -5331,7 +5591,7 @@ get_wide_int (wide_int *) const return false; } -/* The write_reproducer specialization for . */ +/* The write_reproducer specialization for <_Complex double>. */ template <> void @@ -5341,14 +5601,164 @@ write_reproducer (reproducer &r) const char *id = r.make_identifier (this, "rvalue"); double real = creal(m_value); double imag = cimag(m_value); - r.write (" gcc_jit_rvalue *%s =\n" - " gcc_jit_context_new_rvalue_from_complex_double (%s, /* gcc_jit_context *ctxt */\n" - " %s, /* gcc_jit_type *numeric_type */\n" - " %f+%fj); /* double value */\n", + + r.write ( + " gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_rvalue_from_complex_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %.9g + %.9gj */\n" + " CMPLX (",/* ... real, imag)); */ + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + real, imag); + + if (std::isfinite (real)) + r.write("%a,", real); + else if (std::isinf (real)) + { + if (real < 0) + r.write ("-INFINITY,"); + else + r.write ("INFINITY,"); + } + else /* NaN */ + { + /* Store the NaN as a unsigned long long literal. + ull_to_d() will convert it back to double */ + union dull u; + u.d = real; + r.write ("ull_to_d (%#llx),", u.ull); + } + + if (std::isfinite (imag)) + r.write("%a)", imag); + else if (std::isinf (imag)) + { + if (real < 0) + r.write ("-INFINITY)"); + else + r.write ("INFINITY)"); + } + else /* NaN */ + { + union dull u; + u.d = imag; + r.write ("ull_to_d (%#llx))", u.ull); + } + + r.write (");\n\n"); /* Close the function call */ +} + +template <> +string * +memento_of_new_rvalue_from_const <_Complex long double>::make_debug_string () +{ + long double real = creall(m_value); + long double imag = cimagl(m_value); + return string::from_printf (m_ctxt, + "(%s)(%Lg%+Lgj)", + m_type->get_debug_string (), + real, imag); +} + +/* The get_wide_int specialization for <_Complex long double>. */ + +template <> +bool +memento_of_new_rvalue_from_const <_Complex long double>:: +get_wide_int (wide_int *) const +{ + return false; +} + +/* The write_reproducer specialization for <_Complex long double>. */ + +template <> +void +recording::memento_of_new_rvalue_from_const <_Complex long double>:: +write_reproducer (reproducer &r) +{ + union ldarr ureal, uimag; + const char *id = r.make_identifier (this, "rvalue"); + long double real = creall(m_value); + long double imag = cimagl(m_value); + + int has_nan = std::isnan (real) || std::isnan (imag); + + if (has_nan) + { + r.write (" gcc_jit_rvalue *%s;\n", id); + /* Scope for multiple "NaN-arrays" in the source file to not clash */ + r.write (" {\n"); + } + if (std::isnan (real)) + { + /* Write the raw bytes of the long double as an char array + to store it in the source code. + I.e. unsigned char arr[] = {0x1, 0x2, 0x3 ... }; */ + ureal.ld = real; + r.write (" unsigned char arr_real[] = "); + reproducer_write_arr (r, ureal.arr, sizeof ureal.arr); + r.write (";\n"); + } + if (std::isnan (imag)) + { + uimag.ld = imag; + r.write (" unsigned char arr_imag[] = "); + reproducer_write_arr (r, uimag.arr, sizeof uimag.arr); + r.write (";\n"); + } + + if (has_nan) + r.write (" "); /* Definition is outside the scope for NaNs */ + else + r.write (" gcc_jit_rvalue *"); + + r.write ("%s =\n" + " gcc_jit_context_new_rvalue_from_complex_long_double (\n" + " %s, /* gcc_jit_context *ctxt */\n" + " %s, /* gcc_jit_type *numeric_type */\n" + " /* %.9Lg + i*%.9Lg */\n" + " CMPLXL (", id, r.get_identifier (get_context ()), r.get_identifier_as_type (m_type), real, imag); + + if (std::isfinite (real)) + r.write ("%LaL, ", real); + else if (std::isinf (real)) + { + if (real < 0) + r.write ("-INFINITY, "); + else + r.write ("INFINITY, "); + } + else if (std::isnan (real)) + { + /* Convert the char array written above, to a long double */ + r.write ("arr_to_ld (arr_real, sizeof arr_real), "); + } + + if (std::isfinite (imag)) + r.write ("%LaL)", imag); + else if (std::isinf (imag)) + { + if (imag < 0) + r.write ("-INFINITY)"); + else + r.write ("INFINITY)"); + } + else if (std::isnan (imag)) + { + r.write ("arr_to_ld (arr_imag, sizeof arr_imag))"); + } + r.write(");\n\n"); /* Close function call */ + + if (has_nan) + r.write (" }\n"); /* Close NaN-array scope */ } /* The make_debug_string specialization for , rendering it as diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index f95b9ad67d7..5331ea2ad50 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -188,12 +188,18 @@ namespace gccjit int value) const; rvalue new_rvalue (type numeric_type, long value) const; + rvalue new_rvalue (type numeric_type, + long long value) const; rvalue zero (type numeric_type) const; rvalue one (type numeric_type) const; rvalue new_rvalue (type numeric_type, double value) const; + rvalue new_rvalue (type numeric_type, + long double value) const; rvalue new_rvalue (type numeric_type, _Complex double value) const; + rvalue new_rvalue (type numeric_type, + _Complex long double value) const; rvalue new_rvalue (type pointer_type, void *value) const; rvalue new_rvalue (const std::string &value) const; @@ -952,6 +958,17 @@ context::new_rvalue (type numeric_type, value)); } +inline rvalue +context::new_rvalue (type numeric_type, + long long value) const +{ + return rvalue ( + gcc_jit_context_new_rvalue_from_long_long ( + m_inner_ctxt, + numeric_type.get_inner_type (), + value)); +} + inline rvalue context::zero (type numeric_type) const { @@ -976,6 +993,17 @@ context::new_rvalue (type numeric_type, value)); } +inline rvalue +context::new_rvalue (type numeric_type, + long double value) const +{ + return rvalue ( + gcc_jit_context_new_rvalue_from_long_double ( + m_inner_ctxt, + numeric_type.get_inner_type (), + value)); +} + inline rvalue context::new_rvalue (type numeric_type, _Complex double value) const @@ -987,6 +1015,17 @@ context::new_rvalue (type numeric_type, value)); } +inline rvalue +context::new_rvalue (type numeric_type, + _Complex long double value) const +{ + return rvalue ( + gcc_jit_context_new_rvalue_from_complex_long_double ( + m_inner_ctxt, + numeric_type.get_inner_type (), + value)); +} + inline rvalue context::new_rvalue (type pointer_type, void *value) const diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 2c605d0ddf0..76f81aeebd5 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -1982,6 +1982,19 @@ gcc_jit_context_new_rvalue_from_long (gcc_jit_context *ctxt, ->new_rvalue_from_const (numeric_type, value)); } +gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_long_long (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + long long value) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type); + + return ((gcc_jit_rvalue *)ctxt + ->new_rvalue_from_const (numeric_type, value)); +} + /* Public entrypoint. See description in libgccjit.h. This is essentially equivalent to: @@ -2035,6 +2048,19 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, ->new_rvalue_from_const (numeric_type, value)); } +gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_long_double (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + long double value) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type); + + return ((gcc_jit_rvalue *)ctxt + ->new_rvalue_from_const (numeric_type, value)); +} + gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, @@ -2054,6 +2080,26 @@ gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, ->new_rvalue_from_const (numeric_type, value)); } +gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_complex_long_double ( + gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + _Complex long double value) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type); + + RETURN_NULL_IF_FAIL_PRINTF1 ( + numeric_type->is_float (), + ctxt, NULL, + "not a floating point type (type: %s)", + numeric_type->get_debug_string ()); + + return ((gcc_jit_rvalue *)ctxt + ->new_rvalue_from_const <_Complex long double> (numeric_type, value)); +} + /* Public entrypoint. See description in libgccjit.h. diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index cdaec450981..2134c92465e 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1069,6 +1069,16 @@ gcc_jit_context_new_rvalue_from_long (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, long value); +#define LIBGCCJIT_HAVE_LONGLONG_CONSTANTS +/* Get a constant from a long long. + + This function was added in LIBGCCJIT_ABI_26. You can test for + its presence with: + #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS */ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_long_long (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + long long value); extern gcc_jit_rvalue * gcc_jit_context_zero (gcc_jit_context *ctxt, gcc_jit_type *numeric_type); @@ -1083,7 +1093,17 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, double value); -/* Complex floating-point constants. +/* Get a constant from a long double. + + This function was added in LIBGCCJIT_ABI_26. You can test for + its presence with: + #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS */ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_long_double (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + long double value); + +/* Get a constant from a complex double. This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its presence using @@ -1093,6 +1113,17 @@ gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, _Complex double value); +/* Get a constant from a complex long double. + + This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS */ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_complex_long_double ( + gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + _Complex long double value); + /* Pointers. */ extern gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index efa80d9cf2f..aba2d69079f 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -280,5 +280,9 @@ LIBGCCJIT_ABI_25 { LIBGCCJIT_ABI_26 { global: gcc_jit_context_new_rvalue_from_complex_double; + gcc_jit_context_new_rvalue_from_complex_long_double; + gcc_jit_context_new_rvalue_from_long_double; + gcc_jit_context_new_rvalue_from_long_long; gcc_jit_context_set_bool_enable_complex_types; } LIBGCCJIT_ABI_25; + diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index b8693bd5b9c..3880b428c26 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -277,6 +277,13 @@ #undef create_code #undef verify_code +/* test-long-literals.c */ +#define create_code create_code_long_literals +#define verify_code verify_code_long_literals +#include "test-long-literals.c" +#undef create_code +#undef verify_code + /* test-long-string-literal.c */ #define create_code create_code_long_string_literal #define verify_code verify_code_long_string_literal diff --git a/gcc/testsuite/jit.dg/test-long-literals.c b/gcc/testsuite/jit.dg/test-long-literals.c new file mode 100644 index 00000000000..a83af8b0eb1 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-long-literals.c @@ -0,0 +1,283 @@ +/* Test long literals. + + I.e. long long, long double and long complex doubles. + + Also test NaN:s and inf:s with double. */ + + +#include +#include +#include +#include + +#include "libgccjit.h" +#include "harness.h" + +int compare_nans(double d1, double d2) +{ + union {double d; unsigned long long ull;} u1, u2; + + u1.d = d1; + u2.d = d2; + + return u1.ull == u2.ull; +} + +int compare_nansl(long double d1, long double d2) +{ + union { long double ld; unsigned char arr[sizeof (long double)];} + u1 = {.arr = {0}}, + u2 = {.arr = {0}}; + /* Zero the arrs. I don't know if long double zeroes all its size + since some of it is padding. */ + + u1.ld = d1; + u2.ld = d2; + + return memcmp (u1.arr, u2.arr, sizeof u1.arr) == 0; +} + +static void +make_code_lit_cld(gcc_jit_context *ctxt, + const char *fn_name, + int type, + _Complex long double local_val, + int lit_type) +{ + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + /* local_type f1 = local_val; */ + gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1"); + + gcc_jit_rvalue *r1; + + if (lit_type == 'L') + r1 = gcc_jit_context_new_rvalue_from_long_double ( + ctxt, tt, creall(local_val)); + else if (lit_type == 'C') + r1 = gcc_jit_context_new_rvalue_from_complex_long_double ( + ctxt, tt, local_val); + + gcc_jit_block_add_assignment (block, 0, f1, r1); + + gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1)); +} + +static void +make_code_lit_d (gcc_jit_context *ctxt, + const char *fn_name, + int type, + _Complex double local_val, + int lit_type) +{ + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + /* local_type f1 = local_val; */ + gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1"); + + gcc_jit_rvalue *r1; + + if (lit_type == 'd') + r1 = gcc_jit_context_new_rvalue_from_double ( + ctxt, tt, local_val); + else if (lit_type == 'c') + r1 = gcc_jit_context_new_rvalue_from_complex_double ( + ctxt, tt, local_val); + + gcc_jit_block_add_assignment (block, 0, f1, r1); + + gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1)); +} + +static void +make_code_lit_ll (gcc_jit_context *ctxt, + const char *fn_name, + int type, + long long local_val) +{ + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + /* local_type f1 = local_val; */ + gcc_jit_lvalue *f1 = gcc_jit_function_new_local (foo, 0, tt, "f1"); + + gcc_jit_rvalue *r1; + + r1 = gcc_jit_context_new_rvalue_from_long_long ( + ctxt, tt, creall(local_val)); + + gcc_jit_block_add_assignment (block, 0, f1, r1); + + gcc_jit_block_end_with_return (block, 0, gcc_jit_lvalue_as_rvalue(f1)); +} + + +union uu { double d; long long l; } u; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + make_code_lit_cld (ctxt, "long_double_ldlit_1c1", + GCC_JIT_TYPE_LONG_DOUBLE, + -1.1L, 'L'); + make_code_lit_cld (ctxt, "long_double_ldlit_1Ldiv3L", + GCC_JIT_TYPE_LONG_DOUBLE, + 1/3.L, 'L'); + make_code_lit_cld (ctxt, "long_double_ldlit_inf", + GCC_JIT_TYPE_LONG_DOUBLE, + INFINITY, 'L'); + make_code_lit_cld (ctxt, "long_double_ldlit_minf", + GCC_JIT_TYPE_LONG_DOUBLE, + -INFINITY, 'L'); + make_code_lit_cld (ctxt, "long_double_ldlit_nan1", + GCC_JIT_TYPE_LONG_DOUBLE, + nanl("1"), 'L'); + + make_code_lit_cld (ctxt, "complex_long_double_cldlit_1div3_2div3j", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + 1/3.L + 2.Lj/3, 'C'); + + make_code_lit_cld (ctxt, "complex_long_double_cldlit_inf_infj", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + CMPLXL (INFINITY, INFINITY), 'C'); + make_code_lit_cld (ctxt, "complex_long_double_cldlit_minf_minfj", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + CMPLXL (-INFINITY, -INFINITY), 'C'); + make_code_lit_cld (ctxt, "complex_long_double_cldlit_nan1_nan2j", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + CMPLXL (nanl ("1"), nanl ("2")), 'C'); + + make_code_lit_ll (ctxt, "long_long_lllit_2", + GCC_JIT_TYPE_LONG_LONG, + 2); + + make_code_lit_ll (ctxt, "long_long_lllit_min", + GCC_JIT_TYPE_LONG_LONG, + LLONG_MIN); + + make_code_lit_ll (ctxt, "long_long_lllit_max", + GCC_JIT_TYPE_LONG_LONG, + LLONG_MAX); + + make_code_lit_ll (ctxt, "ulong_long_lllit_max", + GCC_JIT_TYPE_UNSIGNED_LONG_LONG, + ULLONG_MAX); + + make_code_lit_d (ctxt, "double_nan1", + GCC_JIT_TYPE_DOUBLE, + nan("1"), 'd'); + make_code_lit_d (ctxt, "double_inf", + GCC_JIT_TYPE_DOUBLE, + INFINITY, 'd'); + make_code_lit_d (ctxt, "double_minf", + GCC_JIT_TYPE_DOUBLE, + -INFINITY, 'd'); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + { + double (*f)() = gcc_jit_result_get_code ( + result, "double_nan1"); + + CHECK(compare_nans (f(), nan("1"))); + } + { + double (*f)() = gcc_jit_result_get_code ( + result, "double_inf"); + + CHECK_VALUE (f(), INFINITY); + } + { + double (*f)() = gcc_jit_result_get_code ( + result, "double_minf"); + + CHECK_VALUE (f(), -INFINITY); + } + { + long double (*f)() = gcc_jit_result_get_code ( + result, "long_double_ldlit_1c1"); + + CHECK_VALUE(f (), -1.1L); + } + { + long double (*f)() = gcc_jit_result_get_code ( + result, "long_double_ldlit_1Ldiv3L"); + + CHECK_VALUE(f (), 1.L/3.L); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code ( + result, "complex_long_double_cldlit_1div3_2div3j"); + + CHECK_VALUE (f(), 1/3.L + 2.Lj/3); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code ( + result, "complex_long_double_cldlit_inf_infj"); + + CHECK_VALUE (f(),CMPLXL (INFINITY, INFINITY)); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code ( + result, "complex_long_double_cldlit_minf_minfj"); + + CHECK_VALUE (f(),CMPLXL (-INFINITY, -INFINITY)); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code ( + result, "complex_long_double_cldlit_nan1_nan2j"); + _Complex double key = CMPLXL (nanl ("1"), nanl ("2")); + _Complex double ans = f(); + + CHECK (compare_nansl (creall (key), creall (ans))); + CHECK (compare_nansl (cimagl (key), cimagl (ans))); + } + { + long long (*f)() = gcc_jit_result_get_code ( + result, "long_long_lllit_2"); + + CHECK_VALUE (f(), 2); + } + { + long long (*f)() = gcc_jit_result_get_code ( + result, "long_long_lllit_min"); + + CHECK_VALUE (f(), LLONG_MIN); + } + { + long long (*f)() = gcc_jit_result_get_code ( + result, "long_long_lllit_max"); + + CHECK_VALUE (f(), LLONG_MAX); + } + { + unsigned long long (*f)() = gcc_jit_result_get_code ( + result, "ulong_long_lllit_max"); + + CHECK_VALUE (f(), ULLONG_MAX); + } +} -- 2.42.0