From bec2b4d30e689e0135b1d71513317a042ab8b770 Mon Sep 17 00:00:00 2001 From: Petter Tomner Date: Wed, 15 Sep 2021 13:19:48 +0200 Subject: [PATCH 1/3] complex --- gcc/jit/docs/topics/contexts.rst | 20 + gcc/jit/docs/topics/expressions.rst | 89 ++- gcc/jit/docs/topics/types.rst | 12 +- gcc/jit/jit-common.h | 1 + gcc/jit/jit-playback.c | 165 ++++- gcc/jit/jit-recording.c | 116 ++- gcc/jit/jit-recording.h | 28 + gcc/jit/libgccjit++.h | 23 +- gcc/jit/libgccjit.c | 97 ++- gcc/jit/libgccjit.h | 45 +- gcc/jit/libgccjit.map | 6 + gcc/testsuite/jit.dg/all-non-failing-tests.h | 30 + gcc/testsuite/jit.dg/test-complex-builtins.c | 217 ++++++ gcc/testsuite/jit.dg/test-complex-literals.c | 145 ++++ gcc/testsuite/jit.dg/test-complex-misc.c | 206 ++++++ gcc/testsuite/jit.dg/test-complex-operators.c | 353 +++++++++ gcc/testsuite/jit.dg/test-complex-types.c | 677 ++++++++++++++++++ 17 files changed, 2188 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-complex-builtins.c create mode 100644 gcc/testsuite/jit.dg/test-complex-literals.c create mode 100644 gcc/testsuite/jit.dg/test-complex-misc.c create mode 100644 gcc/testsuite/jit.dg/test-complex-operators.c create mode 100644 gcc/testsuite/jit.dg/test-complex-types.c diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst index 00fb17e155d..42fdef7c654 100644 --- a/gcc/jit/docs/topics/contexts.rst +++ b/gcc/jit/docs/topics/contexts.rst @@ -489,6 +489,26 @@ Boolean options #ifdef LIBGCCJIT_HAVE_gcc_jit_context_set_bool_use_external_driver +.. function:: void\ + gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt, \ + int bool_value); + + This option can enable complex type support in libgccjit. By default, + no complex types can be used. + + If you use complex types, it is recommended to use builtin functions + `creal`, `cimag` and `conj` etc. with the correct type suffix, since + those are inlined into the code, rather then imported functions from + the math lib which are not. See :ref:`gcc_jit_context_get_builtin_function`. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_16`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_COMPLEX + + Integer options *************** diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 396259ef07e..fc0345c3e1d 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -98,6 +98,15 @@ Simple expressions Given a numeric type (integer or floating point), build an rvalue for the given constant :c:type:`double` value. +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, \ + gcc_jit_type *numeric_type, \ + _Complex double value) + + Given a floating point type, build an rvalue for + the given constant :c:type:`_Complex double`. When the result type is + non-complex, the imaginary part is discarded. + .. function:: gcc_jit_rvalue *\ gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \ gcc_jit_type *pointer_type, \ @@ -168,14 +177,14 @@ Unary Operations The available unary operations are: -========================================== ============ -Unary Operation C equivalent -========================================== ============ -:c:macro:`GCC_JIT_UNARY_OP_MINUS` `-(EXPR)` -:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE` `~(EXPR)` -:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE` `!(EXPR)` -:c:macro:`GCC_JIT_UNARY_OP_ABS` `abs (EXPR)` -========================================== ============ +========================================== ============ ====================== +Unary Operation C equivalent Supported types +========================================== ============ ====================== +:c:macro:`GCC_JIT_UNARY_OP_MINUS` `-(EXPR)` integer, real, complex +:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE` `~(EXPR)` integer +:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE` `!(EXPR)` integer +:c:macro:`GCC_JIT_UNARY_OP_ABS` `abs (EXPR)` integer, real +========================================== ============ ====================== .. c:macro:: GCC_JIT_UNARY_OP_MINUS @@ -235,22 +244,23 @@ Binary Operations The available binary operations are: -======================================== ============ -Binary Operation C equivalent -======================================== ============ -:c:macro:`GCC_JIT_BINARY_OP_PLUS` `x + y` -:c:macro:`GCC_JIT_BINARY_OP_MINUS` `x - y` -:c:macro:`GCC_JIT_BINARY_OP_MULT` `x * y` -:c:macro:`GCC_JIT_BINARY_OP_DIVIDE` `x / y` -:c:macro:`GCC_JIT_BINARY_OP_MODULO` `x % y` -:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND` `x & y` -:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR` `x ^ y` -:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR` `x | y` -:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND` `x && y` -:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR` `x || y` -:c:macro:`GCC_JIT_BINARY_OP_LSHIFT` `x << y` -:c:macro:`GCC_JIT_BINARY_OP_RSHIFT` `x >> y` -======================================== ============ +======================================== ============ ======================= +Binary Operation C equivalent Supported operand types +======================================== ============ ======================= +:c:macro:`GCC_JIT_BINARY_OP_PLUS` `x + y` integer, real, complex +:c:macro:`GCC_JIT_BINARY_OP_MINUS` `x - y` integer, real, complex +:c:macro:`GCC_JIT_BINARY_OP_MULT` `x * y` integer, real, complex +:c:macro:`GCC_JIT_BINARY_OP_DIVIDE` `x / y` integer, real, complex +:c:macro:`GCC_JIT_BINARY_OP_MODULO` `x % y` integer +:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND` `x & y` integer +:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR` `x ^ y` integer +:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR` `x | y` integer +:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND` `x && y` integer +:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR` `x || y` integer +:c:macro:`GCC_JIT_BINARY_OP_LSHIFT` `x << y` integer +:c:macro:`GCC_JIT_BINARY_OP_RSHIFT` `x >> y` integer +:c:macro:`GCC_JIT_BINARY_OP_COMPLEX` `CMPLX (r, i)` real +======================================== =============== ======================= .. c:macro:: GCC_JIT_BINARY_OP_PLUS @@ -378,6 +388,25 @@ Binary Operation C equivalent in C. +.. c:macro:: GCC_JIT_BINARY_OP_COMPLEX + + Create a complex floating point value from + two real floating point values with the same + size qualifier as the complex result type. + I.e two floats for a _Complex float, etc. + + Analogous to: + CMPLX (real,imag) + in C. + + The first operand is the real part, the other + the imaginary. Negative zeroes are preserved + and Inf:s do not lead to NaNs. + + This operator was added in LIBGCCJIT_ABI_16; + you can test for its presence using + `#ifdef LIBGCCJIT_HAVE_COMPLEX` + Comparisons *********** @@ -402,6 +431,7 @@ Comparison C equivalent :c:macro:`GCC_JIT_COMPARISON_GE` `x >= y` ======================================= ============ + Note: Only `==` and `!=` are defined for complex types. Function calls ************** @@ -504,10 +534,17 @@ Type-coercion Currently only a limited set of conversions are possible: - * int <-> float - * int <-> bool + * integer <-> integer + * floating point <-> floating point + * integer <-> floating point + * integer <-> bool * P* <-> Q*, for pointer types P and Q + Note: "floating point" includes complex types. + + When a complex type is converted to a non-complex type, the + imaginary part is discarded. + Lvalues ------- diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst index 831f11b679a..5b5ba050658 100644 --- a/gcc/jit/docs/topics/types.rst +++ b/gcc/jit/docs/topics/types.rst @@ -82,11 +82,17 @@ Standard types :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR` C type: ``(const char *)`` :c:data:`GCC_JIT_TYPE_SIZE_T` C's ``size_t`` type :c:data:`GCC_JIT_TYPE_FILE_PTR` C type: ``(FILE *)`` - :c:data:`GCC_JIT_TYPE_COMPLEX_FLOAT` C99's ``_Complex float`` - :c:data:`GCC_JIT_TYPE_COMPLEX_DOUBLE` C99's ``_Complex double`` - :c:data:`GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE` C99's ``_Complex long double`` + :c:data:`GCC_JIT_TYPE_COMPLEX_FLOAT` C99's ``_Complex float``, ABI 16 + :c:data:`GCC_JIT_TYPE_COMPLEX_DOUBLE` C99's ``_Complex double``, ABI 16 + :c:data:`GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE` C99's ``_Complex long double``, ABI 16 ========================================== ================================ + The complex types are available from :ref:`LIBGCCJIT_ABI_16` after + setting :ref:`gcc_jit_context_set_bool_enable_complex_types`. + + You can test for complex types support with the define + `#ifdef LIBGCCJIT_HAVE_COMPLEX`. + .. function:: gcc_jit_type *\ gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \ int num_bytes, int is_signed) diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h index f88e6755b00..bc0453fba05 100644 --- a/gcc/jit/jit-common.h +++ b/gcc/jit/jit-common.h @@ -198,6 +198,7 @@ enum inner_bool_option { INNER_BOOL_OPTION_ALLOW_UNREACHABLE_BLOCKS, INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER, + INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES, NUM_INNER_BOOL_OPTIONS }; diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 59399dee251..8e4971958c3 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "gcc.h" #include "diagnostic.h" #include "stmt.h" +#include "complex.h" #include @@ -78,6 +79,8 @@ convert (tree dst_type, tree expr) case INTEGER_TYPE: case ENUMERAL_TYPE: return fold (convert_to_integer (dst_type, expr)); + case REAL_TYPE: + return fold (convert_to_real (dst_type, expr)); default: gcc_assert (gcc::jit::active_playback_ctxt); @@ -679,6 +682,24 @@ new_global_initialized (location *loc, namespace playback { +/* Return the corrensponding not complex float type of a + float type. I.e. complex float -> float */ +static tree +complex_real_to_real (tree complex_type) +{ + if (TYPE_CANONICAL (complex_type) == + TYPE_CANONICAL (complex_float_type_node)) + return float_type_node; + else if (TYPE_CANONICAL (complex_type) == + TYPE_CANONICAL (complex_double_type_node)) + return double_type_node; + else if (TYPE_CANONICAL (complex_type) == + TYPE_CANONICAL (complex_long_double_type_node)) + return long_double_type_node; + else + gcc_unreachable(); +} + /* Specialization of making an rvalue from a const, for host . */ template <> @@ -694,6 +715,25 @@ new_rvalue_from_const (type *type, tree inner = build_int_cst (inner_type, value); return new rvalue (this, inner); } + else if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + REAL_VALUE_TYPE real_value; + REAL_VALUE_TYPE imag_value; + + real_type = complex_real_to_real (inner_type); + + real_from_integer (&real_value, VOIDmode, value, SIGNED); + real_from_integer (&imag_value, VOIDmode, 0, SIGNED); + + 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 { REAL_VALUE_TYPE real_value; @@ -718,6 +758,25 @@ new_rvalue_from_const (type *type, tree inner = build_int_cst (inner_type, value); return new rvalue (this, inner); } + else if (COMPLEX_FLOAT_TYPE_P (inner_type)) + { + tree tree_real; + tree tree_imag; + tree real_type; + REAL_VALUE_TYPE real_value; + REAL_VALUE_TYPE imag_value; + + real_type = complex_real_to_real (inner_type); + + real_from_integer (&real_value, VOIDmode, value, SIGNED); + real_from_integer (&imag_value, VOIDmode, 0, SIGNED); + + 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 { REAL_VALUE_TYPE real_value; @@ -743,19 +802,104 @@ new_rvalue_from_const (type *type, real.c:real_from_target appears to require the representation to be split into 32-bit values, and then sent as an pair of host long ints. */ + + union + { + double as_double; + uint32_t as_uint32s[2]; + } u_real, u_imag; + + u_real.as_double = value; + long int as_long_ints[2]; + as_long_ints[0] = u_real.as_uint32s[0]; + as_long_ints[1] = u_real.as_uint32s[1]; + REAL_VALUE_TYPE real_value; + real_from_target (&real_value, as_long_ints, DFmode); + + 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[2]; + u_imag.as_double = 0.; + zero_as_long_ints[0] = u_imag.as_uint32s[0]; + zero_as_long_ints[1] = u_imag.as_uint32s[1]; + + real_from_target (&imag_value, zero_as_long_ints, DFmode); + + 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 <> +rvalue * +context:: +new_rvalue_from_const <_Complex double> (type *type, + _Complex double value) +{ + tree inner_type = type->as_tree (); + union { double as_double; uint32_t as_uint32s[2]; - } u; - u.as_double = value; + } u_real, u_imag; + + u_real.as_double = creal(value); long int as_long_ints[2]; - as_long_ints[0] = u.as_uint32s[0]; - as_long_ints[1] = u.as_uint32s[1]; + as_long_ints[0] = u_real.as_uint32s[0]; + as_long_ints[1] = u_real.as_uint32s[1]; + + REAL_VALUE_TYPE real_value; real_from_target (&real_value, as_long_ints, DFmode); - tree inner = build_real (inner_type, real_value); - return new rvalue (this, inner); + + 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[2]; + u_imag.as_double = cimag(value); + value_as_long_ints[0] = u_imag.as_uint32s[0]; + value_as_long_ints[1] = u_imag.as_uint32s[1]; + + real_from_target (&imag_value, value_as_long_ints, DFmode); + + 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 . */ @@ -985,6 +1129,11 @@ new_binary_op (location *loc, case GCC_JIT_BINARY_OP_RSHIFT: inner_op = RSHIFT_EXPR; break; + + /* Create complex value from two real values */ + case GCC_JIT_BINARY_OP_COMPLEX: + inner_op = COMPLEX_EXPR; + break; } tree inner_expr = build2 (inner_op, @@ -1163,6 +1312,10 @@ playback::context::build_cast (playback::location *loc, build_int_cst (TREE_TYPE (t_expr), 0)); goto maybe_fold; + case COMPLEX_TYPE: + t_ret = convert_to_complex (t_dst_type, t_expr); + goto maybe_fold; + case REAL_TYPE: t_ret = convert_to_real (t_dst_type, t_expr); goto maybe_fold; diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 117ff70114c..565d078d517 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -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" @@ -1609,7 +1610,8 @@ static const char * const static const char * const inner_bool_option_reproducer_strings[NUM_INNER_BOOL_OPTIONS] = { "gcc_jit_context_set_bool_allow_unreachable_blocks", - "gcc_jit_context_set_bool_use_external_driver" + "gcc_jit_context_set_bool_use_external_driver", + "gcc_jit_context_set_bool_enable_complex_types" }; /* Write the current value of all options to the log file (if any). */ @@ -2423,6 +2425,59 @@ recording::memento_of_get_type::is_float () const } } +/* Implementation of pure virtual hook recording::type::is_complex for + recording::memento_of_get_type. */ + +bool +recording::memento_of_get_type::is_complex () const +{ + switch (m_kind) + { + default: gcc_unreachable (); + + case GCC_JIT_TYPE_VOID: + return false; + + case GCC_JIT_TYPE_VOID_PTR: + return false; + + case GCC_JIT_TYPE_BOOL: + return false; + + case GCC_JIT_TYPE_CHAR: + case GCC_JIT_TYPE_SIGNED_CHAR: + case GCC_JIT_TYPE_UNSIGNED_CHAR: + case GCC_JIT_TYPE_SHORT: + case GCC_JIT_TYPE_UNSIGNED_SHORT: + case GCC_JIT_TYPE_INT: + case GCC_JIT_TYPE_UNSIGNED_INT: + case GCC_JIT_TYPE_LONG: + case GCC_JIT_TYPE_UNSIGNED_LONG: + case GCC_JIT_TYPE_LONG_LONG: + case GCC_JIT_TYPE_UNSIGNED_LONG_LONG: + return false; + + case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_DOUBLE: + case GCC_JIT_TYPE_LONG_DOUBLE: + return false; + + case GCC_JIT_TYPE_CONST_CHAR_PTR: + return false; + + case GCC_JIT_TYPE_SIZE_T: + return false; + + case GCC_JIT_TYPE_FILE_PTR: + return false; + + case GCC_JIT_TYPE_COMPLEX_FLOAT: + case GCC_JIT_TYPE_COMPLEX_DOUBLE: + case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE: + return true; + } +} + /* Implementation of pure virtual hook recording::type::is_bool for recording::memento_of_get_type. */ @@ -4704,6 +4759,7 @@ recording::global::write_reproducer (reproducer &r) 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 ; /* Implementation of the pure virtual hook recording::memento::replay_into @@ -4881,6 +4937,51 @@ recording::memento_of_new_rvalue_from_const ::write_reproducer (reproduc m_value); } +/* The make_debug_string specialization for , rendering it as + (TARGET_TYPE)LITERAL + e.g. + "(complex float)(42.0+42.0j)". */ + +template <> +string * +memento_of_new_rvalue_from_const <_Complex double>::make_debug_string () +{ + double real = creal(m_value); + double imag = cimag(m_value); + return string::from_printf (m_ctxt, + "(%s)(%g%+gj)", + m_type->get_debug_string (), + real, imag); +} + +/* The get_wide_int specialization for . */ + +template <> +bool +memento_of_new_rvalue_from_const <_Complex double>::get_wide_int (wide_int *) const +{ + return false; +} + +/* The write_reproducer specialization for . */ + +template <> +void +recording::memento_of_new_rvalue_from_const <_Complex double>::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", + id, + r.get_identifier (get_context ()), + r.get_identifier_as_type (m_type), + real, imag); +} + /* The make_debug_string specialization for , rendering it as (TARGET_TYPE)HEX e.g. @@ -5178,13 +5279,20 @@ static const char * const binary_op_strings[] = { "||", /* GCC_JIT_BINARY_OP_LOGICAL_OR */ "<<", /* GCC_JIT_BINARY_OP_LSHIFT */ ">>", /* GCC_JIT_BINARY_OP_RSHIFT */ + "", /* GCC_JIT_BINARY_OP_COMPLEX - dummy not used */ }; recording::string * recording::binary_op::make_debug_string () { enum precedence prec = get_precedence (); - return string::from_printf (m_ctxt, + if (m_op == GCC_JIT_BINARY_OP_COMPLEX) + return string::from_printf (m_ctxt, + "(%s + %s * _Imaginary_I)", + m_a->get_debug_string_parens (prec), + m_b->get_debug_string_parens (prec)); + else + return string::from_printf (m_ctxt, "%s %s %s", m_a->get_debug_string_parens (prec), binary_op_strings[m_op], @@ -5203,7 +5311,8 @@ const char * const binary_op_reproducer_strings[] = { "GCC_JIT_BINARY_OP_LOGICAL_AND", "GCC_JIT_BINARY_OP_LOGICAL_OR", "GCC_JIT_BINARY_OP_LSHIFT", - "GCC_JIT_BINARY_OP_RSHIFT" + "GCC_JIT_BINARY_OP_RSHIFT", + "GCC_JIT_BINARY_OP_COMPLEX", }; /* Implementation of recording::memento::write_reproducer for binary ops. */ @@ -5244,6 +5353,7 @@ static const enum precedence binary_op_precedence[] = { PRECEDENCE_LOGICAL_OR, /* GCC_JIT_BINARY_OP_LOGICAL_OR */ PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_LSHIFT */ PRECEDENCE_SHIFT, /* GCC_JIT_BINARY_OP_RSHIFT */ + PRECEDENCE_CAST, /* GCC_JIT_BINARY_OP_COMPLEX */ }; } /* namespace recording */ diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 03fa1160cf0..d5e0c359a48 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -544,10 +544,14 @@ public: virtual bool is_int () const = 0; virtual bool is_float () const = 0; virtual bool is_bool () const = 0; + virtual bool is_complex () const = 0; virtual type *is_pointer () = 0; virtual type *is_array () = 0; virtual bool is_void () const { return false; } virtual bool has_known_size () const { return true; } + /* Used to pair complex float types with real float type + of the same "base type". */ + virtual int float_size_qual () const { return 0; } bool is_numeric () const { @@ -598,9 +602,28 @@ public: return type::accepts_writes_from (rtype); } + int float_size_qual () const FINAL OVERRIDE + { + switch (m_kind) + { + default: + return 0; + case GCC_JIT_TYPE_FLOAT: + case GCC_JIT_TYPE_COMPLEX_FLOAT: + return 1; + case GCC_JIT_TYPE_DOUBLE: + case GCC_JIT_TYPE_COMPLEX_DOUBLE: + return 2; + case GCC_JIT_TYPE_LONG_DOUBLE: + case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE: + return 3; + } + } + bool is_int () const FINAL OVERRIDE; bool is_float () const FINAL OVERRIDE; bool is_bool () const FINAL OVERRIDE; + bool is_complex () const FINAL OVERRIDE; type *is_pointer () FINAL OVERRIDE { return dereference (); } type *is_array () FINAL OVERRIDE { return NULL; } bool is_void () const FINAL OVERRIDE { return m_kind == GCC_JIT_TYPE_VOID; } @@ -635,6 +658,7 @@ public: bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } + bool is_complex () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return m_other_type; } type *is_array () FINAL OVERRIDE { return NULL; } @@ -661,6 +685,7 @@ public: bool is_int () const FINAL OVERRIDE { return m_other_type->is_int (); } bool is_float () const FINAL OVERRIDE { return m_other_type->is_float (); } bool is_bool () const FINAL OVERRIDE { return m_other_type->is_bool (); } + bool is_complex () const FINAL OVERRIDE { return m_other_type->is_complex (); } type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); } type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); } @@ -771,6 +796,7 @@ class array_type : public type bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } + bool is_complex () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return m_element_type; } int num_elements () { return m_num_elements; } @@ -805,6 +831,7 @@ public: bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } + bool is_complex () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return NULL; } @@ -918,6 +945,7 @@ public: bool is_int () const FINAL OVERRIDE { return false; } bool is_float () const FINAL OVERRIDE { return false; } bool is_bool () const FINAL OVERRIDE { return false; } + bool is_complex () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return NULL; } diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 82831ff5da0..6be5a9b9cc3 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -128,7 +128,8 @@ namespace gccjit void set_bool_allow_unreachable_blocks (int bool_value); void set_bool_use_external_driver (int bool_value); - + void set_bool_enable_complex_types (int bool_value); + void add_command_line_option (const char *optname); void add_driver_option (const char *optname); @@ -191,6 +192,8 @@ namespace gccjit rvalue one (type numeric_type) const; rvalue new_rvalue (type numeric_type, double value) const; + rvalue new_rvalue (type numeric_type, + _Complex double value) const; rvalue new_rvalue (type pointer_type, void *value) const; rvalue new_rvalue (const std::string &value) const; @@ -732,6 +735,13 @@ context::set_bool_use_external_driver (int bool_value) bool_value); } +inline void +context::set_bool_enable_complex_types (int bool_value) +{ + gcc_jit_context_set_bool_enable_complex_types (m_inner_ctxt, + bool_value); +} + inline void context::add_command_line_option (const char *optname) { @@ -950,6 +960,17 @@ context::new_rvalue (type numeric_type, value)); } +inline rvalue +context::new_rvalue (type numeric_type, + _Complex double value) const +{ + return rvalue ( + gcc_jit_context_new_rvalue_from_complex_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.c b/gcc/jit/libgccjit.c index 7fa948007ad..0859b38f609 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -448,9 +448,17 @@ gcc_jit_context_get_type (gcc_jit_context *ctxt, JIT_LOG_FUNC (ctxt->get_logger ()); RETURN_NULL_IF_FAIL_PRINTF1 ( (type >= GCC_JIT_TYPE_VOID - && type <= GCC_JIT_TYPE_FILE_PTR), + && type <= GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE), ctxt, NULL, "unrecognized value for enum gcc_jit_types: %i", type); + if (type >= GCC_JIT_TYPE_COMPLEX_FLOAT + && type <= GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE) + RETURN_NULL_IF_FAIL ( + ctxt->get_inner_bool_option( + gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES), + ctxt, NULL, + "complex type are only available after enabling them with" + " gcc_jit_context_set_bool_enable_complex_types()"); return (gcc_jit_type *)ctxt->get_type (type); } @@ -1320,6 +1328,26 @@ 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_complex_double (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + double _Complex 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 (numeric_type, value)); +} + + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the @@ -1415,6 +1443,14 @@ gcc_jit_context_new_unary_op (gcc_jit_context *ctxt, result_type->get_debug_string ()); RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); + if (rvalue->get_type ()->is_complex ()) + RETURN_NULL_IF_FAIL_PRINTF2 ( + op == GCC_JIT_UNARY_OP_MINUS, + ctxt, loc, + "only unary minus defined for complex types: %s (type: %s)", + rvalue->get_debug_string (), + rvalue->get_type ()->get_debug_string ()); + return (gcc_jit_rvalue *)ctxt->new_unary_op (loc, op, result_type, rvalue); } @@ -1426,7 +1462,7 @@ static bool valid_binary_op_p (enum gcc_jit_binary_op op) { return (op >= GCC_JIT_BINARY_OP_PLUS - && op <= GCC_JIT_BINARY_OP_RSHIFT); + && op <= GCC_JIT_BINARY_OP_COMPLEX); } /* Public entrypoint. See description in libgccjit.h. @@ -1470,6 +1506,38 @@ gcc_jit_context_new_binary_op (gcc_jit_context *ctxt, a->get_debug_string (), b->get_debug_string (), result_type->get_debug_string ()); + if (op == GCC_JIT_BINARY_OP_COMPLEX) + { + RETURN_NULL_IF_FAIL ( + result_type->is_complex (), + ctxt, loc, + "return type is not complex"); + RETURN_NULL_IF_FAIL_PRINTF3 ( + !a->get_type ()->is_complex () && + a->get_type ()->is_float (), + ctxt, loc, + "first operand of %s is not real: %s (type: %s)", + gcc::jit::binary_op_reproducer_strings[op], + a->get_debug_string (), + a->get_type ()->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF3 ( + !b->get_type ()->is_complex () && + b->get_type ()->is_float (), + ctxt, loc, + "2nd operand of %s is not real: %s (type: %s)", + gcc::jit::binary_op_reproducer_strings[op], + b->get_debug_string (), + b->get_type ()->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF2 ( + a->get_type ()-> float_size_qual () == + result_type->float_size_qual (), + ctxt, loc, + "size qualifiers of complex operand's not the same as the result:" + " operands: %s, result: %s", + a->get_type ()->get_debug_string (), + result_type->get_debug_string ()); + } + return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b); } @@ -1506,6 +1574,14 @@ gcc_jit_context_new_comparison (gcc_jit_context *ctxt, b->get_debug_string (), b->get_type ()->get_debug_string ()); + if (a->get_type ()->is_complex()) + RETURN_NULL_IF_FAIL_PRINTF1 ( + (op == GCC_JIT_COMPARISON_EQ + || op == GCC_JIT_COMPARISON_NE), + ctxt, loc, + "invalid enum gcc_jit_comparison for complex operands: %i", + op); + return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b); } @@ -2735,6 +2811,23 @@ gcc_jit_context_set_bool_allow_unreachable_blocks (gcc_jit_context *ctxt, bool_value); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::set_inner_bool_option method in + jit-recording.c. */ + +void +gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt, + int bool_value) +{ + RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + ctxt->set_inner_bool_option ( + gcc::jit::INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES, + bool_value); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 5c722c2c57f..f3d2c40d8be 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -848,6 +848,17 @@ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, double value); +/* Complex floating-point constants. + + This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_COMPLEX +*/ +extern gcc_jit_rvalue * +gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, + gcc_jit_type *numeric_type, + double _Complex value); + /* Pointers. */ extern gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, @@ -959,7 +970,26 @@ enum gcc_jit_binary_op /* Right shift; analogous to: (EXPR_A) >> (EXPR_B) in C. */ - GCC_JIT_BINARY_OP_RSHIFT + GCC_JIT_BINARY_OP_RSHIFT, + + /* Create a complex floating point value from + two real floating point values. The operands + and the result need to have the same size + qualifier. + + Analogous to: + CMPLX (real,imag) + in C. + + The first operand is the real part, the other + the imaginary. Negative zeroes are preserved + and Inf:s do not lead to NaNs. + + This operator was added in LIBGCCJIT_ABI_16; + you can test for its presence using + #ifdef LIBGCCJIT_HAVE_COMPLEX + */ + GCC_JIT_BINARY_OP_COMPLEX }; extern gcc_jit_rvalue * @@ -1434,6 +1464,19 @@ gcc_jit_timer_print (gcc_jit_timer *timer, FILE *f_out); +#define LIBGCCJIT_HAVE_COMPLEX + +/* Enables complex type support in libgccjit. + + This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_COMPLEX +*/ + +extern void +gcc_jit_context_set_bool_enable_complex_types (gcc_jit_context *ctxt, + int bool_value); + #define LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call /* Mark/clear a call as needing tail-call optimization. diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 337ea6c7fe4..c9b044dc8f5 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -205,3 +205,9 @@ LIBGCCJIT_ABI_15 { gcc_jit_extended_asm_add_clobber; gcc_jit_context_add_top_level_asm; } LIBGCCJIT_ABI_14; + +LIBGCCJIT_ABI_16 { + global: + gcc_jit_context_new_rvalue_from_complex_double; + gcc_jit_context_set_bool_enable_complex_types; +} LIBGCCJIT_ABI_15; \ No newline at end of file diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 84ef54a0386..7b45acd4b9c 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -105,6 +105,36 @@ #undef create_code #undef verify_code +/* test-complex-builtins.c */ +#define create_code create_code_complex_builtins +#define verify_code verify_code_complex_builtins +#include "test-complex-builtins.c" +#undef create_code +#undef verify_code + +/* test-complex-literals.c */ +#define create_code create_code_complex_literals +#define verify_code verify_code_complex_literals +#include "test-complex-literals.c" +#undef create_code +#undef verify_code + +/* test-complex-misc.c */ +#define create_code create_code_complex_misc +#define verify_code verify_code_complex_misc +#include "test-complex-misc.c" +#undef create_code +#undef verify_code + +/* test-complex-operators.c */ +#define create_code create_code_complex_operators +#define verify_code verify_code_complex_operators +#include "test-complex-operators.c" +#undef create_code +#undef verify_code + +/* test-complex-types.c: Quite long, don't include here */ + /* test-compound-assignment.c */ #define create_code create_code_compound_assignment #define verify_code verify_code_compound_assignment diff --git a/gcc/testsuite/jit.dg/test-complex-builtins.c b/gcc/testsuite/jit.dg/test-complex-builtins.c new file mode 100644 index 00000000000..fce2c9b2d09 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-builtins.c @@ -0,0 +1,217 @@ +/* + This test just checks that the builtins cimag, creal and + conj are usable. + + Also, they should be inlined, which can be checked by + disassembling the object file manually. +*/ + +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +static void +make_code_unop_builtins (gcc_jit_context *ctxt, + const char *fn_name, + int type_return, + int type_arg, + gcc_jit_function *fn) +{ + gcc_jit_block *block; + + gcc_jit_type *tr = gcc_jit_context_get_type (ctxt, type_return); + gcc_jit_type *ta = gcc_jit_context_get_type (ctxt, type_arg); + + gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, ta, "f1"); + + gcc_jit_param *params[] = {param1}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tr, fn_name, 1, params, 0); + + block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param (foo, 0)); + + gcc_jit_rvalue *args[] = { + gcc_jit_lvalue_as_rvalue (f1) + }; + + /* return fn(f1); */ + gcc_jit_rvalue *r = gcc_jit_context_new_call + (ctxt, 0, fn, + 1, + args); + + gcc_jit_block_end_with_return (block, 0, r); +} + +static void +make_code_binop_builtins (gcc_jit_context *ctxt, + const char *fn_name, + int type1, + int type2, + gcc_jit_function *builtin) +{ + gcc_jit_block *block; + + gcc_jit_type *t1 = gcc_jit_context_get_type (ctxt, type1); + gcc_jit_type *t2 = gcc_jit_context_get_type (ctxt, type2); + + gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, t1, "f1"); + gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, t2, "f2"); + + gcc_jit_param *params[] = {param1, param2}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + t1, fn_name, 2, params, 0); + + block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param(foo, 0)); + gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param(foo, 1)); + + gcc_jit_rvalue *args[] = { + gcc_jit_lvalue_as_rvalue (f1), + gcc_jit_lvalue_as_rvalue (f2) + }; + + /* return builtin(f1,f2); */ + gcc_jit_rvalue *r = gcc_jit_context_new_call + (ctxt, 0, builtin, + 2, + args); + + gcc_jit_block_end_with_return (block, 0, r); +} + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + gcc_jit_function *fn_cpow = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_cpow"); + + make_code_binop_builtins (ctxt, "cpow_builtin", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + fn_cpow); + + gcc_jit_function *fn_conj = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_conj"); + + /* In a good world conj should be inlined */ + make_code_unop_builtins (ctxt, "conj_inlined", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + fn_conj); + + gcc_jit_function *fn_creal = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_creal"); + gcc_jit_function *fn_crealf = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_crealf"); + gcc_jit_function *fn_creall = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_creall"); + gcc_jit_function *fn_cimag = gcc_jit_context_get_builtin_function + (ctxt, "__builtin_cimag"); + + /* These should be inlined too */ + make_code_unop_builtins (ctxt, "creal_inlined", + GCC_JIT_TYPE_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + fn_creal); + make_code_unop_builtins (ctxt, "cimag_inlined", + GCC_JIT_TYPE_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + fn_cimag); + + make_code_unop_builtins (ctxt, "crealf_inlined", + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + fn_crealf); + make_code_unop_builtins (ctxt, "creall_inlined", + GCC_JIT_TYPE_LONG_DOUBLE, + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + fn_creall); + + /* Use to inspect code manually and assure conj, creal, cimag + are inlined. At the time of writing they are on my x64 machine */ + #if 0 + gcc_jit_context_compile_to_file (ctxt, GCC_JIT_OUTPUT_KIND_OBJECT_FILE, + "test-complex-builtins.o"); + #endif +} + +typedef _Complex double (*cd_cdcd)(_Complex double, _Complex double); +typedef _Complex double (*cd_cd)(_Complex double); +typedef double (*d_cd)(_Complex double); +typedef float (*f_cf)(_Complex float); +typedef long double (*ld_cld)(_Complex long double); + +/* We need this to fool GCC into not precomputing the built-in ... + precomputing seems like a feuture libgccjit misses. */ +volatile _Complex double half = 0.5; + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + {/* Test binary builtins */ + { + cd_cdcd fn = + gcc_jit_result_get_code (result, "cpow_builtin"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (2, 2), 4.); + _Complex double ans = fn (-1., 0.5); + _Complex double key = __builtin_cpow (-1., half); + + /* This test fails if libgccjit can precompute builtins */ + CHECK_VALUE (ans, key); /* Almost 1.j */ + } + } + {/* Test unary builtins */ + { /* conj */ + cd_cd fn = gcc_jit_result_get_code (result, "conj_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE( fn (1. - 1.j), 1. + 1.j); + } + { /* creal */ + d_cd fn = gcc_jit_result_get_code (result, "creal_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. - 1.j), 1.); + } + { /* cimag */ + d_cd fn = gcc_jit_result_get_code (result, "cimag_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. - 1.j), -1.); + } + { /* crealf */ + f_cf fn = gcc_jit_result_get_code (result, "crealf_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f - 1.fj), 1.f); + } + { /* creall */ + ld_cld fn = gcc_jit_result_get_code (result, "creall_inlined"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.L - 1.Lj), 1.L); + } + } +} diff --git a/gcc/testsuite/jit.dg/test-complex-literals.c b/gcc/testsuite/jit.dg/test-complex-literals.c new file mode 100644 index 00000000000..422cff1048d --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-literals.c @@ -0,0 +1,145 @@ +/* + Test the new 'gcc_jit_context_new_rvalue_from_complex_double()' + aswell as test that the old '_from_int ... _from_double" + can produce complex values. +*/ + +#include +#include + +#include "libgccjit.h" +#include "harness.h" + +static void +make_code (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 == 'c') + r1 = gcc_jit_context_new_rvalue_from_complex_double (ctxt, tt, local_val); + else if (lit_type == 'd') + r1 = gcc_jit_context_new_rvalue_from_double (ctxt, tt, creal(local_val)); + else if (lit_type == 'l') + r1 = gcc_jit_context_new_rvalue_from_long (ctxt, tt, creal(local_val)); + else if (lit_type == 'i') + r1 = gcc_jit_context_new_rvalue_from_int (ctxt, tt, creal(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)); +} + +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 (ctxt, "complex_float_clit_1c1_2c2j", + GCC_JIT_TYPE_COMPLEX_FLOAT, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "complex_double_clit_1c1_2c2j", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "complex_long_double_clit_1c1_2c2j", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "float_clit_1c1", + GCC_JIT_TYPE_FLOAT, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "double_clit_1c1", + GCC_JIT_TYPE_DOUBLE, + 1.1 + 2.2j, 'c'); + make_code (ctxt, "long_double_clit_1c1", + GCC_JIT_TYPE_LONG_DOUBLE, + 1.1 + 2.2j, 'c'); + + /* Make complex from "from_double", "from_long","from_int" */ + make_code (ctxt, "complex_float_dlit_1c1", + GCC_JIT_TYPE_COMPLEX_FLOAT, + 1.1, 'd'); + make_code (ctxt, "complex_double_dlit_1c1", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + 1.1, 'd'); + make_code (ctxt, "complex_long_double_dlit_1c1", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + 1.1, 'd'); + make_code (ctxt, "complex_double_llit_2", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + 2, 'l'); + make_code (ctxt, "complex_double_ilit_3", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + 3, 'i'); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + {/* Test literals */ + { + _Complex float (*f)() = gcc_jit_result_get_code (result, "complex_float_clit_1c1_2c2j"); + + CHECK_VALUE(f (), 1.1f + 2.2fj); + } + { + _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_clit_1c1_2c2j"); + CHECK_VALUE(f (), 1.1 + 2.2j); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_clit_1c1_2c2j"); + /* Note: The literal in the function is complex double */ + CHECK_VALUE(f (),1.1 + 2.2j); + } + { + float (*f)() = gcc_jit_result_get_code (result, "float_clit_1c1"); + CHECK_VALUE(f (), 1.1f); + } + { + double (*f)() = gcc_jit_result_get_code (result, "double_clit_1c1"); + CHECK_VALUE(f (), 1.1); + } + { + long double (*f)() = gcc_jit_result_get_code (result, "long_double_clit_1c1"); + CHECK_VALUE(f (), 1.1); + } + { + float (*f)() = gcc_jit_result_get_code (result, "complex_float_dlit_1c1"); + CHECK_VALUE(f (), 1.1f); + } + { + _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_dlit_1c1"); + CHECK_VALUE(f (), 1.1); + } + { + _Complex long double (*f)() = gcc_jit_result_get_code (result, "complex_long_double_dlit_1c1"); + /* Note: The literal in the function is complex double */ + CHECK_VALUE(f (), 1.1); + } + { + _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_llit_2"); + CHECK_VALUE(f (), 2); + } + { + _Complex double (*f)() = gcc_jit_result_get_code (result, "complex_double_ilit_3"); + CHECK_VALUE(f (), 3); + } + } +} diff --git a/gcc/testsuite/jit.dg/test-complex-misc.c b/gcc/testsuite/jit.dg/test-complex-misc.c new file mode 100644 index 00000000000..c35275b21de --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-misc.c @@ -0,0 +1,206 @@ +/* + This test checks wether complex types work with structs, unions + and pointers. + + Aswell as const and volatile, but only in the sense that having + those qualifiers doesn't crash gcc. + +*/ + +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + gcc_jit_type *type_int = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *type_cd = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE); + + gcc_jit_lvalue *cd_gbl = gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + type_cd, + "a_complex_global_double_2"); + + /* These globals are not used for anything */ + gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + gcc_jit_type_get_volatile (type_cd), + "a_volatile_complex_double"); + gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + gcc_jit_type_get_const (type_cd), + "a_const_complex_double"); + + gcc_jit_type *arr_type = + gcc_jit_context_new_array_type (ctxt, + 0, type_cd, 10); + gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + arr_type, + "a_const_complex_double_array"); + + {/* Make a function returning union with 3.14 + 1516.j in it */ + gcc_jit_field *cd_field = + gcc_jit_context_new_field (ctxt, + 0, + type_cd, + "cd"); + gcc_jit_field *i_field = + gcc_jit_context_new_field (ctxt, + 0, + type_int, + "i"); + gcc_jit_field *fields[] = {cd_field, i_field}; + gcc_jit_type *cdi = + gcc_jit_context_new_union_type (ctxt, + 0, + "cdi", + 2, + fields); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + cdi, "a_uniony_fn_returning_union", 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + gcc_jit_lvalue *local = + gcc_jit_function_new_local (foo, 0, cdi, "union_local"); + gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field + (local, 0, cd_field); + gcc_jit_block_add_assignment + (block, 0, lv_field, + gcc_jit_context_new_rvalue_from_complex_double ( + ctxt, type_cd, 3.14 + 1592.j)); + + /* Note: Writes to global here */ + gcc_jit_block_add_assignment ( + block, 0, cd_gbl, + gcc_jit_context_new_rvalue_from_complex_double ( + ctxt, type_cd, 6535 + 9.j)); + + gcc_jit_block_end_with_return ( + block, 0, gcc_jit_lvalue_as_rvalue (local)); + } + {/* Make a function returning a complexy struct */ + gcc_jit_field *cd_field = + gcc_jit_context_new_field (ctxt, + 0, + type_cd, + "cd"); + gcc_jit_field *i_field = + gcc_jit_context_new_field (ctxt, + 0, + type_int, + "i"); + gcc_jit_field *fields[] = {cd_field, i_field}; + gcc_jit_type *cdi_struct = + gcc_jit_struct_as_type( + gcc_jit_context_new_struct_type (ctxt, + 0, + "cdi_struct", + 2, + fields)); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + cdi_struct, "a_structy_fn_returning_struct", 0, 0, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + gcc_jit_lvalue *local = + gcc_jit_function_new_local (foo, 0, cdi_struct, "local"); + gcc_jit_lvalue *lv_field = gcc_jit_lvalue_access_field ( + local, 0, cd_field); + gcc_jit_block_add_assignment ( + block, 0, lv_field, + /* Note: Reads from global here */ + gcc_jit_lvalue_as_rvalue(cd_gbl)); + + gcc_jit_block_end_with_return ( + block, 0, gcc_jit_lvalue_as_rvalue (local)); + } + {/* Make a function taking a pointer to a complex double, + add 1+1.j to it, and return the pointer */ + gcc_jit_type *type_return = + gcc_jit_type_get_pointer (type_cd); + + gcc_jit_param *param = gcc_jit_context_new_param ( + ctxt, 0, gcc_jit_type_get_pointer (type_cd), "pcd"); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + type_return, + "a_pointy_fn_returning_points", 1, ¶m, 0); + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_rvalue *param_rv = gcc_jit_param_as_rvalue ( + gcc_jit_function_get_param (foo, 0)); + + gcc_jit_rvalue *rval = gcc_jit_context_new_binary_op ( + ctxt, 0, GCC_JIT_BINARY_OP_PLUS, type_cd, + gcc_jit_context_new_rvalue_from_complex_double ( + ctxt, type_cd, 1 + 1.j), + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference ( + param_rv, 0))); + gcc_jit_block_add_assignment (block, 0, + gcc_jit_rvalue_dereference ( + param_rv, 0), + rval); + + gcc_jit_block_end_with_return ( + block, 0, param_rv); + } + + gcc_jit_context_compile_to_file (ctxt, GCC_JIT_OUTPUT_KIND_OBJECT_FILE, "misc.o"); +} + +typedef union { + _Complex double cd; + int i; +} complex_test_union; + +typedef struct { + _Complex double cd; + int i; +} complex_test_struct; + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + { + complex_test_union (*fn)() = gcc_jit_result_get_code (result, "a_uniony_fn_returning_union"); + CHECK_NON_NULL (fn); + + complex_test_union u = fn(); + CHECK_VALUE (u.cd, 3.14 + 1592.j); + } + { + complex_test_struct (*fn)() = gcc_jit_result_get_code (result, "a_structy_fn_returning_struct"); + CHECK_NON_NULL (fn); + + complex_test_struct s = fn(); + CHECK_VALUE (s.cd, 6535 + 9.j); + } + { + _Complex double * + (*fn)(_Complex double *) = gcc_jit_result_get_code (result, "a_pointy_fn_returning_points"); + CHECK_NON_NULL (fn); + + _Complex double s = 2. + 3.i; + _Complex double *p = fn(&s); + CHECK_VALUE (p, &s); + CHECK_VALUE (s, 3. + 4.i); + } +} diff --git a/gcc/testsuite/jit.dg/test-complex-operators.c b/gcc/testsuite/jit.dg/test-complex-operators.c new file mode 100644 index 00000000000..091b56fb4d2 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-operators.c @@ -0,0 +1,353 @@ +/* + Test ==, !=, the create-complex-from-reals-operator, + unary minus and *-/+ + */ + + +#include +#include + +#include "libgccjit.h" +#include "harness.h" + +static void +make_code_compop (gcc_jit_context *ctxt, + const char *fn_name, + int type, + enum gcc_jit_comparison op) +{ + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, type); + gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL); + + gcc_jit_param *param1 = gcc_jit_context_new_param (ctxt, 0, tt, "f1"); + gcc_jit_param *param2 = gcc_jit_context_new_param (ctxt, 0, tt, "f2"); + + gcc_jit_param *params[] = {param1, param2}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + bool_type, fn_name, 2, params, 0); + + gcc_jit_block *block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param (foo, 0)); + gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue ( + gcc_jit_function_get_param (foo, 1)); + + /* return f1 op f2; */ + gcc_jit_rvalue *rcompop = gcc_jit_context_new_comparison + (ctxt, 0, op, + gcc_jit_lvalue_as_rvalue (f1), + gcc_jit_lvalue_as_rvalue (f2)); + + gcc_jit_block_end_with_return (block, 0, rcompop); +} + +static void +make_code_binop (gcc_jit_context *ctxt, + const char *fn_name, + int type1, + int type2, + int return_type, + enum gcc_jit_binary_op op) +{ + gcc_jit_type *tt1 = gcc_jit_context_get_type(ctxt, type1); + gcc_jit_type *tt2 = gcc_jit_context_get_type(ctxt, type2); + gcc_jit_type *tr = gcc_jit_context_get_type(ctxt, return_type); + + gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt1, "f1"); + gcc_jit_param *param2 = gcc_jit_context_new_param(ctxt, 0, tt2, "f2"); + + gcc_jit_param *params[] = {param1, param2}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tr, fn_name, 2, params, 0); + + gcc_jit_block *block = gcc_jit_function_new_block(foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue( + gcc_jit_function_get_param(foo, 0)); + gcc_jit_lvalue *f2 = gcc_jit_param_as_lvalue( + gcc_jit_function_get_param(foo, 1)); + + /* return f1 op f2; */ + gcc_jit_rvalue *rbinop = gcc_jit_context_new_binary_op + (ctxt, 0, op, tr, + gcc_jit_lvalue_as_rvalue (f1), + gcc_jit_lvalue_as_rvalue (f2)); + + gcc_jit_block_end_with_return (block, 0, rbinop); +} + +static void +make_code_unop (gcc_jit_context *ctxt, + const char *fn_name, + int type1, + enum gcc_jit_unary_op op) +{ + gcc_jit_type *tt = gcc_jit_context_get_type(ctxt, type1); + + gcc_jit_param *param1 = gcc_jit_context_new_param(ctxt, 0, tt, "f1"); + + gcc_jit_param *params[] = {param1}; + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 1, params, 0); + + gcc_jit_block *block = gcc_jit_function_new_block(foo, "start"); + + gcc_jit_lvalue *f1 = gcc_jit_param_as_lvalue( + gcc_jit_function_get_param(foo, 0)); + + /* return op f1; */ + gcc_jit_rvalue *rbinop = gcc_jit_context_new_unary_op + (ctxt, 0, op, tt, + gcc_jit_lvalue_as_rvalue (f1)); + + gcc_jit_block_end_with_return (block, 0, rbinop); +} + +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_binop (ctxt, "plus_complex_float_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_PLUS); + make_code_binop (ctxt, "minus_complex_float_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_MINUS); + make_code_binop (ctxt, "div_complex_float_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_DIVIDE); + make_code_binop (ctxt, "mul_complex_float_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_MULT); + + make_code_binop (ctxt, "cmplx_float_float", + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_BINARY_OP_COMPLEX); + + /* Unundef to test different error msgs */ +#if 0 + make_code_binop (ctxt, "should_not_work", + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_FLOAT, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_BINARY_OP_COMPLEX); +#endif + + make_code_binop (ctxt, "cmplx_double_double", + GCC_JIT_TYPE_DOUBLE, + GCC_JIT_TYPE_DOUBLE, + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_BINARY_OP_COMPLEX); + + make_code_binop (ctxt, "cmplx_long_double_long_double", + GCC_JIT_TYPE_LONG_DOUBLE, + GCC_JIT_TYPE_LONG_DOUBLE, + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + GCC_JIT_BINARY_OP_COMPLEX); + + make_code_unop (ctxt, "minus_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_UNARY_OP_MINUS); + + make_code_compop (ctxt, "equal_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_COMPARISON_EQ); + make_code_compop (ctxt, "nequal_complex_float", + GCC_JIT_TYPE_COMPLEX_FLOAT, + GCC_JIT_COMPARISON_NE); + make_code_compop (ctxt, "equal_complex_double", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_COMPARISON_EQ); + make_code_compop (ctxt, "nequal_complex_double", + GCC_JIT_TYPE_COMPLEX_DOUBLE, + GCC_JIT_COMPARISON_NE); + make_code_compop (ctxt, "equal_complex_long_double", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + GCC_JIT_COMPARISON_EQ); + make_code_compop (ctxt, "nequal_complex_long_double", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + GCC_JIT_COMPARISON_NE); + + /* Unundef to test different error msgs */ +#if 0 + make_code_compop (ctxt, "qweasdzxc", + GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, + GCC_JIT_COMPARISON_GE); +#endif + +} + +typedef _Complex float (*cf_cfcf)(_Complex float, _Complex float); +typedef _Complex float (*cf_cf)(_Complex float); +typedef _Bool (*b_cfcf)(_Complex float, _Complex float); +typedef _Bool (*b_cdcd)(_Complex double, _Complex double); +typedef _Bool (*b_cldcld)(_Complex long double, _Complex long double); + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + (void) ctxt; + CHECK_NON_NULL (result); + + {/* Test binary operators */ + { + cf_cfcf fn = + gcc_jit_result_get_code (result, "plus_complex_float_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) + (3.f + 4.fj)); + } + { + cf_cfcf fn = + gcc_jit_result_get_code (result, "minus_complex_float_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj) - (3.f + 4.fj)); + } + { + cf_cfcf fn = + gcc_jit_result_get_code (result, "div_complex_float_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)/(3.f + 4.fj)); + } + { + cf_cfcf fn = + gcc_jit_result_get_code (result, "mul_complex_float_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 3.f + 4.fj), (1.f + 2.fj)*(3.f + 4.fj)); + } + { + _Complex float (*fn)(float, float) = + gcc_jit_result_get_code (result, "cmplx_float_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1, 2), 1.f + 2.fi); + /* Note that the real answer is 0 not nan as it would have been by + multiplying INF * 1.fi */ + CHECK_VALUE (fn (0, INFINITY), CMPLXF (0, INFINITY)); + CHECK_VALUE (fn (0, -INFINITY), CMPLXF (0, -INFINITY)); + + CHECK_VALUE (crealf (fn (0, NAN)), crealf (CMPLXF (0, NAN))); + CHECK (isnanf (cimagf (fn (0, NAN)))); + + /* -0 need be preserved */ + _Complex float f = fn (0, -0.); + CHECK (signbit ( cimagf (f)) != 0); + CHECK_VALUE (f, CMPLXF (0, -0.)); + } + { + _Complex double (*fn)(double, double) = + gcc_jit_result_get_code (result, "cmplx_double_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1, 2), 1. + 2.i); + CHECK_VALUE (fn (0, INFINITY), CMPLX (0, INFINITY)); + CHECK_VALUE (fn (0, -INFINITY), CMPLX (0, -INFINITY)); + + CHECK_VALUE (creal (fn (0, NAN)), creal (CMPLX (0, NAN))); + CHECK (isnan (cimag (fn (0, NAN)))); + + _Complex double f = fn (0, -0.); + CHECK (signbit (cimag (f)) != 0); + CHECK_VALUE (f, CMPLXF (0, -0.)); + } + { + _Complex long double (*fn)(long double, long double) = + gcc_jit_result_get_code (result, "cmplx_long_double_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1, 2), 1.L + 2.Li); + CHECK_VALUE (fn (0, INFINITY), CMPLXL (0, INFINITY)); + CHECK_VALUE (fn (0, -INFINITY), CMPLXL (0, -INFINITY)); + + CHECK_VALUE (creall (fn (0, NAN)), creall (CMPLXL (0, NAN))); + CHECK (isnanl (cimagl (fn (0, NAN)))); + + _Complex long double f = fn (0, -0.); + CHECK (signbit (cimag (f)) != 0); + CHECK_VALUE (f, CMPLXL (0, -0.)); + } + } + + {/* Test unary ops */ + { + cf_cf fn = + gcc_jit_result_get_code (result, "minus_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj), -(1.f + 2.fj)); + } + } + {/* Test comp ops */ + { + b_cfcf fn = + gcc_jit_result_get_code (result, "equal_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 1); + CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 0); + } + { + b_cfcf fn = + gcc_jit_result_get_code (result, "nequal_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.f + 2.fj, 1.f + 2.fj ), 0); + CHECK_VALUE (fn (1.f + 3.fj, 1.f + 2.fj ), 1); + } + { + b_cdcd fn = + gcc_jit_result_get_code (result, "equal_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1); + CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0); + } + { + b_cdcd fn = + gcc_jit_result_get_code (result, "nequal_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0); + CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1); + } + { + b_cldcld fn = + gcc_jit_result_get_code (result, "equal_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 1); + CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 0); + } + { + b_cldcld fn = + gcc_jit_result_get_code (result, "nequal_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1. + 2.j, 1. + 2.j ), 0); + CHECK_VALUE (fn (1. + 3.j, 1. + 2.j ), 1); + } + } +} diff --git a/gcc/testsuite/jit.dg/test-complex-types.c b/gcc/testsuite/jit.dg/test-complex-types.c new file mode 100644 index 00000000000..c555133367b --- /dev/null +++ b/gcc/testsuite/jit.dg/test-complex-types.c @@ -0,0 +1,677 @@ +/* + Test cast from all complex types to all primitive types + except bool and amongst the complex types them self. + + Also test some cast from non-complex to complex. + + Also call a mathlib complex function and create a + complex global. + */ + +#include +#include + +#include "libgccjit.h" +#include "harness.h" + +/* + Make code 1: (check that function calls works) + complex float csqrtf(complex float f); + + complex float complex_float_foo(complex float f) + { + return csqrtf( f * (complex float)2.); + } + + Make code 2: (check casts) + int float complex_float_to_int (complex float f) + { + return f; + } + + with different types and function names. + */ + + +static void +make_code1(gcc_jit_context* ctxt, + const char *fn_name, + const char *sqrt_fn, + int type) +{ + gcc_jit_rvalue *rval1, *rval2; + gcc_jit_block *block; + + gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, type); + gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f"); + gcc_jit_function *func = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_IMPORTED, + ct, sqrt_fn, 1, ¶m, 0); + + param = gcc_jit_context_new_param (ctxt, 0, ct, "f"); + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + ct, fn_name, 1, ¶m, 0); + + block = gcc_jit_function_new_block (foo, "start"); + + rval1 = gcc_jit_context_new_binary_op (ctxt, 0, GCC_JIT_BINARY_OP_MULT, ct, + gcc_jit_param_as_rvalue ( + gcc_jit_function_get_param (foo, 0)), + gcc_jit_context_new_rvalue_from_double (ctxt, ct, 2.)); + + rval2 = gcc_jit_context_new_call (ctxt, 0, func, 1, &rval1); + + gcc_jit_block_end_with_return (block, 0, rval2); +} + +static void +make_code2 (gcc_jit_context *ctxt, + const char *fn_name, + int complex_type, + int target_type) +{ + gcc_jit_block *block; + gcc_jit_type *tt = gcc_jit_context_get_type (ctxt, target_type); + gcc_jit_type *ct = gcc_jit_context_get_type (ctxt, complex_type); + + gcc_jit_param *param = gcc_jit_context_new_param (ctxt, 0, ct, "f"); + + gcc_jit_function *foo = gcc_jit_context_new_function (ctxt, 0, + GCC_JIT_FUNCTION_EXPORTED, + tt, fn_name, 1, ¶m, 0); + + block = gcc_jit_function_new_block (foo, "start"); + + gcc_jit_block_end_with_return (block, 0, + gcc_jit_context_new_cast (ctxt, 0, + gcc_jit_param_as_rvalue ( + gcc_jit_function_get_param (foo, 0)), tt)); +} + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + (void) user_data; + + gcc_jit_context_set_bool_enable_complex_types (ctxt, 1); + + gcc_jit_context_new_global ( + ctxt, 0, GCC_JIT_GLOBAL_EXPORTED, + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE), + "a_complex_global_double"); + + make_code1 (ctxt, "complex_float_foo", "csqrtf", GCC_JIT_TYPE_COMPLEX_FLOAT); + make_code1 (ctxt, "complex_double_foo", "csqrt", GCC_JIT_TYPE_COMPLEX_DOUBLE); + make_code1 (ctxt, "complex_long_double_foo", "csqrtl", GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE); + +#define MAKE_CODE_2(name ,complex_type, target_type)\ + make_code2 (ctxt, #name, GCC_JIT_TYPE_ ## complex_type, GCC_JIT_TYPE_ ## target_type); + +#define MAKE_CODE_2_OUTER(name, type)\ + MAKE_CODE_2(name ## _to_char, type, CHAR)\ + MAKE_CODE_2(name ## _to_long_double, type, LONG_DOUBLE)\ + MAKE_CODE_2(name ## _to_double, type, DOUBLE)\ + MAKE_CODE_2(name ## _to_float, type, FLOAT)\ + MAKE_CODE_2(name ## _to_signed_char, type, SIGNED_CHAR)\ + MAKE_CODE_2(name ## _to_short, type, SHORT)\ + MAKE_CODE_2(name ## _to_int, type, INT)\ + MAKE_CODE_2(name ## _to_long, type, LONG)\ + MAKE_CODE_2(name ## _to_long_long, type, LONG_LONG)\ + MAKE_CODE_2(name ## _to_u_char, type, UNSIGNED_CHAR)\ + MAKE_CODE_2(name ## _to_u_short, type, UNSIGNED_SHORT)\ + MAKE_CODE_2(name ## _to_u_int, type, UNSIGNED_INT)\ + MAKE_CODE_2(name ## _to_u_long, type, UNSIGNED_LONG)\ + MAKE_CODE_2(name ## _to_u_long_long, type, UNSIGNED_LONG_LONG)\ + MAKE_CODE_2(name ## _to_complex_float, type, COMPLEX_FLOAT)\ + MAKE_CODE_2(name ## _to_complex_double, type, COMPLEX_DOUBLE)\ + MAKE_CODE_2(name ## _to_complex_long_double, type, COMPLEX_LONG_DOUBLE) + + /* Test all these casts */ + MAKE_CODE_2_OUTER (complex_float, COMPLEX_FLOAT) + MAKE_CODE_2_OUTER (complex_double, COMPLEX_DOUBLE) + MAKE_CODE_2_OUTER (complex_long_double, COMPLEX_LONG_DOUBLE) + + /* Test some of these casts */ + MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG) + MAKE_CODE_2_OUTER(float, FLOAT) + MAKE_CODE_2_OUTER(int, INT) + + /* Writing the reproducer takes annoyingly long time with all these + functions bellow, so #if them out. */ +#if 0 + MAKE_CODE_2_OUTER(long_double,LONG_DOUBLE) + MAKE_CODE_2_OUTER(double, DOUBLE) + MAKE_CODE_2_OUTER(long_long, LONG_LONG) + MAKE_CODE_2_OUTER(long, LONG) + MAKE_CODE_2_OUTER(short, UNSIGNED_SHORT) + MAKE_CODE_2_OUTER(signed_char, SIGNED_CHAR) + MAKE_CODE_2_OUTER(unsigned_long_long, UNSIGNED_LONG_LONG) + MAKE_CODE_2_OUTER(unsigned_long, UNSIGNED_LONG) + MAKE_CODE_2_OUTER(unsigned_int, UNSIGNED_INT) + MAKE_CODE_2_OUTER(unsigned_short, UNSIGNED_SHORT) + MAKE_CODE_2_OUTER(unsigned_char, UNSIGNED_CHAR) + + MAKE_CODE_2_OUTER(char, CHAR) + /* Note: No bool */ +#endif + +#undef MAKE_CODE_2 +#undef MAKE_CODE_2_OUTER +} + +typedef complex long double (*ld_foop)(); +typedef complex double (*d_foop)(); +typedef complex float (*f_foop)(); + +#define FOO_to_BAR(foo, foo_txt) \ +typedef long long (* foo_txt ## _to_ll)(_Complex foo);\ +typedef long (* foo_txt ## _to_l)(_Complex foo);\ +typedef int (* foo_txt ## _to_i)(_Complex foo);\ +typedef short (* foo_txt ## _to_h)(_Complex foo);\ +typedef signed char (* foo_txt ## _to_sc)(_Complex foo);\ +typedef char (* foo_txt ## _to_c)(_Complex foo);\ +typedef unsigned long long (* foo_txt ## _to_ull)(_Complex foo);\ +typedef unsigned long (* foo_txt ## _to_ul)(_Complex foo);\ +typedef unsigned int (* foo_txt ## _to_ui)(_Complex foo);\ +typedef unsigned short (* foo_txt ## _to_uh)(_Complex foo);\ +typedef unsigned char (* foo_txt ## _to_uc)(_Complex foo);\ +typedef double (* foo_txt ## _to_d)(_Complex foo);\ +typedef float (* foo_txt ## _to_f)(_Complex foo);\ +typedef long double (* foo_txt ## _to_ld)(_Complex foo);\ +typedef _Complex double (* foo_txt ## _to_cd)(_Complex foo);\ +typedef _Complex float (* foo_txt ## _to_cf)(_Complex foo);\ +typedef _Complex long double (* foo_txt ## _to_cld)(_Complex foo);\ +typedef _Bool (* foo_txt ## _to_b)(_Complex foo); + +FOO_to_BAR (float, cf) +FOO_to_BAR (double, cd) +FOO_to_BAR (long double, cld) + +#undef FOO_to_BAR + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + { + {/* Just check that we can get the global. */ + _Complex double *d = gcc_jit_result_get_global (result, "a_complex_global_double"); + CHECK_NON_NULL (d); + } + } + {/* Check the square rooty thing. */ + { + d_foop d_foop = gcc_jit_result_get_code (result, "complex_double_foo"); + CHECK_NON_NULL (d_foop); + + complex double q = 2. + 2.i; + complex double ref = csqrt (q * 2.); + complex double ans = d_foop (q); + CHECK_VALUE (ref, ans); + } + { + f_foop f_foop = gcc_jit_result_get_code (result, "complex_float_foo"); + CHECK_NON_NULL (f_foop); + + complex float q = 2.f + 2.fi; + complex float ref = csqrtf (q * 2.f); + complex float ans = f_foop (q); + CHECK_VALUE (ref, ans); + } + { + ld_foop ld_foop = gcc_jit_result_get_code (result, "complex_long_double_foo"); + CHECK_NON_NULL (ld_foop); + + complex long double q = 2.L + 2.Li; + complex long double ref = csqrtl (q * 2.L); + complex long double ans = ld_foop (q); + CHECK_VALUE (ref, ans); + } + } + /* With the power of M-w C-y */ + + {/* Cast hither and thither */ + { + cf_to_ld fn = gcc_jit_result_get_code (result, "complex_float_to_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f); + CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f); + } + { + cf_to_d fn = gcc_jit_result_get_code (result, "complex_float_to_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f); + CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f); + } + { + cf_to_f fn = gcc_jit_result_get_code (result, "complex_float_to_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.fi), 1.1f); + CHECK_VALUE (fn (0.f + 2.2fi), 0.f); + } + { + cf_to_ll fn = gcc_jit_result_get_code (result, "complex_float_to_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_l fn = gcc_jit_result_get_code (result, "complex_float_to_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_i fn = gcc_jit_result_get_code (result, "complex_float_to_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_h fn = gcc_jit_result_get_code (result, "complex_float_to_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_sc fn = gcc_jit_result_get_code (result, "complex_float_to_signed_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_c fn = gcc_jit_result_get_code (result, "complex_float_to_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_ull fn = gcc_jit_result_get_code (result, "complex_float_to_u_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_ul fn = gcc_jit_result_get_code (result, "complex_float_to_u_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_ui fn = gcc_jit_result_get_code (result, "complex_float_to_u_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_uh fn = gcc_jit_result_get_code (result, "complex_float_to_u_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + { + cf_to_uc fn = gcc_jit_result_get_code (result, "complex_float_to_u_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1); + CHECK_VALUE (fn (1.1f + 0.fi), 1); + CHECK_VALUE (fn (0.f + 2.2fi), 0); + } + } + + {/* complex double to ... */ + { + cd_to_ld fn = gcc_jit_result_get_code (result, "complex_double_to_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1); + CHECK_VALUE (fn (0.0 + 2.2i), 0.); + } + { + cd_to_d fn = gcc_jit_result_get_code (result, "complex_double_to_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f); + CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f); + } + { + cd_to_f fn = gcc_jit_result_get_code (result, "complex_double_to_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1f + 2.2fi), 1.1f); + CHECK_VALUE (fn (1.1f + 0.0fi), 1.1f); + CHECK_VALUE (fn (0.0f + 2.2fi), 0.0f); + } + { + cd_to_ll fn = gcc_jit_result_get_code (result, "complex_double_to_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_l fn = gcc_jit_result_get_code (result, "complex_double_to_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_i fn = gcc_jit_result_get_code (result, "complex_double_to_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_h fn = gcc_jit_result_get_code (result, "complex_double_to_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_sc fn = gcc_jit_result_get_code (result, "complex_double_to_signed_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_c fn = gcc_jit_result_get_code (result, "complex_double_to_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_ull fn = gcc_jit_result_get_code (result, "complex_double_to_u_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_ul fn = gcc_jit_result_get_code (result, "complex_double_to_u_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_ui fn = gcc_jit_result_get_code (result, "complex_double_to_u_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_uh fn = gcc_jit_result_get_code (result, "complex_double_to_u_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cd_to_uc fn = gcc_jit_result_get_code (result, "complex_double_to_u_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + } + + {/* complex long double to ... */ + { + cld_to_ld fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.); + } + { + cld_to_d fn = gcc_jit_result_get_code (result, "complex_long_double_to_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.); + } + { + cld_to_f fn = gcc_jit_result_get_code (result, "complex_long_double_to_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.); + } + { + cld_to_ll fn = gcc_jit_result_get_code (result, "complex_long_double_to_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_l fn = gcc_jit_result_get_code (result, "complex_long_double_to_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_i fn = gcc_jit_result_get_code (result, "complex_long_double_to_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_h fn = gcc_jit_result_get_code (result, "complex_long_double_to_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_sc fn = gcc_jit_result_get_code (result, "complex_long_double_to_signed_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_c fn = gcc_jit_result_get_code (result, "complex_long_double_to_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_ull fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_ul fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_long"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_ui fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_int"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_uh fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_short"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + { + cld_to_uc fn = gcc_jit_result_get_code (result, "complex_long_double_to_u_char"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1); + CHECK_VALUE (fn (1.1 + 0.0i), 1); + CHECK_VALUE (fn (0.0 + 2.2i), 0); + } + } + + { /* Try casting complex types to complex types */ + { + cld_to_cld fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1L + 2.2Li); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1L + 0.0Li); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.0L + 2.2Li); + } + { + cld_to_cd fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1 + 2.2i); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1 + 0.0i); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.0 + 2.2i); + } + { + cld_to_cf fn = gcc_jit_result_get_code (result, "complex_long_double_to_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1L + 2.2Li), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1L + 0.0Li), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0L + 2.2Li), 0.0f + 2.2fi); + } + { + cd_to_cld fn = gcc_jit_result_get_code (result, "complex_double_to_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i); + } + { + cd_to_cd fn = gcc_jit_result_get_code (result, "complex_double_to_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1 + 2.2i); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1 + 0.0i); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0 + 2.2i); + } + { + cd_to_cf fn = gcc_jit_result_get_code (result, "complex_double_to_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi); + } + { + cf_to_cld fn = gcc_jit_result_get_code (result, "complex_float_to_complex_long_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi); + } + { + cf_to_cd fn = gcc_jit_result_get_code (result, "complex_float_to_complex_double"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi); + } + { + cf_to_cf fn = gcc_jit_result_get_code (result, "complex_float_to_complex_float"); + CHECK_NON_NULL (fn); + + CHECK_VALUE (fn (1.1 + 2.2i), 1.1f + 2.2fi); + CHECK_VALUE (fn (1.1 + 0.0i), 1.1f + 0.0fi); + CHECK_VALUE (fn (0.0 + 2.2i), 0.0f + 2.2fi); + } + } + + {/* Test some of the non-complex to non-complex/complex casts */ + { + _Complex float(*fn)(float) = gcc_jit_result_get_code (result, "float_to_complex_float"); + CHECK_VALUE ( fn(3.f), 3.f); + } + { + _Complex float(*fn)(int) = gcc_jit_result_get_code (result, "int_to_complex_float"); + CHECK_VALUE ( fn(-3), -3.f); + } + { + _Complex double(*fn)(unsigned long) = gcc_jit_result_get_code (result, "unsigned_long_to_complex_double"); + CHECK_VALUE ( fn(3), 3.f); + } + { + double(*fn)(int) = gcc_jit_result_get_code (result, "int_to_double"); + CHECK_VALUE ( fn(3), 3.f); + } + { + int(*fn)(float) = gcc_jit_result_get_code (result, "float_to_int"); + CHECK_VALUE ( fn(3.), 3); + } + } +} -- 2.30.2 From c67c027ce553291594133ab7e9e70b5960570bac Mon Sep 17 00:00:00 2001 From: Petter Tomner Date: Thu, 16 Sep 2021 09:04:07 +0200 Subject: [PATCH 2/3] WIP --- gcc/jit/docs/topics/expressions.rst | 45 +- gcc/jit/jit-playback.c | 145 +++++- gcc/jit/jit-recording.c | 468 +++++++++++++++++-- gcc/jit/libgccjit.c | 46 ++ gcc/jit/libgccjit.h | 39 +- gcc/jit/libgccjit.map | 3 + gcc/testsuite/jit.dg/all-non-failing-tests.h | 7 + gcc/testsuite/jit.dg/test-long-literals.c | 283 +++++++++++ 8 files changed, 996 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-long-literals.c diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index fc0345c3e1d..42f608feb04 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -70,6 +70,18 @@ Simple expressions Given a numeric type (integer or floating point), build an rvalue for the given constant :c:type:`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 :c:type:`long long` value. + + This function was added in :ref:`LIBGCCJIT_ABI_16`; + you can test for its presence using + `#ifdef LIBGCCJIT_HAVE_LONGLONG_CONSTANTS` + .. function:: gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \ gcc_jit_type *numeric_type) @@ -99,7 +111,19 @@ Simple expressions the given constant :c:type:`double` value. .. function:: gcc_jit_rvalue *\ - gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, \ + 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 :c:type:`long double`. + + This function was added in :ref:`LIBGCCJIT_ABI_16`; + you can test for its presence using + `#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, \ _Complex double value) @@ -107,6 +131,23 @@ Simple expressions the given constant :c:type:`_Complex double`. When the result type is non-complex, the imaginary part is discarded. + This function was added in :ref:`LIBGCCJIT_ABI_16`; + you can test for its presence using + `#ifdef LIBGCCJIT_HAVE_COMPLEX` + +.. function:: 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); + + Given a floating point type, build an rvalue for + the given constant :c:type:`_Complex long double`. When the result type is + non-complex, the imaginary part is discarded. + + This function was added in :ref:`LIBGCCJIT_ABI_16`; + you can test for its presence using + `#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, \ @@ -403,7 +444,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_16; + This operator was added in :ref:`LIBGCCJIT_ABI_16`; you can test for its presence using `#ifdef LIBGCCJIT_HAVE_COMPLEX` diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 8e4971958c3..f62cfc5c804 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -61,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. + That means 6 longs to store a long double. We'll make it 8 to + be safe with padding. */ +#define N_LONGS_LDOUBLE 8 + /* 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 @@ -743,15 +750,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)) { @@ -786,6 +792,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 <> @@ -847,6 +864,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 (int 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 (int 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 . */ @@ -854,7 +930,7 @@ template <> rvalue * context:: new_rvalue_from_const <_Complex double> (type *type, - _Complex double value) + _Complex double value) { tree inner_type = type->as_tree (); @@ -902,6 +978,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 (int 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 (int 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.c b/gcc/jit/jit-recording.c index 565d078d517..9d07062131e 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see #include #include +#include #include "jit-builtins.h" #include "jit-recording.h" @@ -1734,8 +1735,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 prunning 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"); @@ -4758,8 +4799,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 @@ -4896,6 +4940,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. @@ -4906,7 +5014,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); } @@ -4920,6 +5028,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 <> @@ -4927,14 +5047,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 @@ -4949,37 +5209,189 @@ memento_of_new_rvalue_from_const <_Complex double>::make_debug_string () double real = creal(m_value); double imag = cimag(m_value); return string::from_printf (m_ctxt, - "(%s)(%g%+gj)", - m_type->get_debug_string (), - real, imag); + "(%s)(%g%+gj)", + m_type->get_debug_string (), + real, imag); } /* The get_wide_int specialization for . */ template <> bool -memento_of_new_rvalue_from_const <_Complex double>::get_wide_int (wide_int *) const +memento_of_new_rvalue_from_const <_Complex double>:: +get_wide_int (wide_int *) const { return false; } -/* The write_reproducer specialization for . */ +/* The write_reproducer specialization for <_Complex double>. */ template <> void -recording::memento_of_new_rvalue_from_const <_Complex double>::write_reproducer (reproducer &r) +recording::memento_of_new_rvalue_from_const <_Complex double>:: +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 @@ -5288,15 +5700,15 @@ recording::binary_op::make_debug_string () enum precedence prec = get_precedence (); if (m_op == GCC_JIT_BINARY_OP_COMPLEX) return string::from_printf (m_ctxt, - "(%s + %s * _Imaginary_I)", - m_a->get_debug_string_parens (prec), - m_b->get_debug_string_parens (prec)); + "(%s + %s * _Imaginary_I)", + m_a->get_debug_string_parens (prec), + m_b->get_debug_string_parens (prec)); else return string::from_printf (m_ctxt, - "%s %s %s", - m_a->get_debug_string_parens (prec), - binary_op_strings[m_op], - m_b->get_debug_string_parens (prec)); + "%s %s %s", + m_a->get_debug_string_parens (prec), + binary_op_strings[m_op], + m_b->get_debug_string_parens (prec)); } const char * const binary_op_reproducer_strings[] = { diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 0859b38f609..9b4e847c499 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -1275,6 +1275,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: @@ -1328,6 +1341,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, @@ -1347,6 +1373,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 f3d2c40d8be..49e359f420c 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -834,6 +834,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_16. You can test for + its presens 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); @@ -847,17 +857,36 @@ extern gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, double value); + +/* Get a constant from a long double. + + This function was added in LIBGCCJIT_ABI_16. 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); -/* Complex floating-point constants. +/* Get a constant from a complex double. This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its presence using - #ifdef LIBGCCJIT_HAVE_COMPLEX -*/ + #ifdef LIBGCCJIT_HAVE_COMPLEX */ extern gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_complex_double (gcc_jit_context *ctxt, - gcc_jit_type *numeric_type, - double _Complex value); + gcc_jit_type *numeric_type, + _Complex double value); +/* Get a constant from a complex long double. + + This API entrypoint was added in LIBGCCJIT_ABI_16; 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 * diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index c9b044dc8f5..4022dbb6fbc 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -209,5 +209,8 @@ LIBGCCJIT_ABI_15 { LIBGCCJIT_ABI_16 { global: gcc_jit_context_new_rvalue_from_complex_double; + gcc_jit_context_new_rvalue_from_complex_long_double; gcc_jit_context_set_bool_enable_complex_types; + gcc_jit_context_new_rvalue_from_long_double; + gcc_jit_context_new_rvalue_from_long_long; } LIBGCCJIT_ABI_15; \ No newline at end of file diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 7b45acd4b9c..8416b312bad 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -239,6 +239,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.30.2 From b152e32a0f3f45699a95c552562a15d693cc8e1b Mon Sep 17 00:00:00 2001 From: Petter Tomner Date: Mon, 20 Sep 2021 17:47:26 +0200 Subject: [PATCH 3/3] global init --- gcc/jit/jit-playback.c | 95 ++- gcc/jit/jit-playback.h | 11 + gcc/jit/jit-recording.c | 198 +++++++ gcc/jit/jit-recording.h | 86 ++- gcc/jit/libgccjit.c | 32 + gcc/jit/libgccjit.h | 12 + gcc/jit/libgccjit.map | 4 +- .../jit.dg/test-global-init-rvalue.c | 554 ++++++++++++++++++ 8 files changed, 982 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-global-init-rvalue.c diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index f62cfc5c804..dd9a7f117cd 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -605,6 +605,71 @@ new_global (location *loc, return global_finalize_lvalue (inner); } +void +playback::context:: +global_set_init_rvalue (lvalue* global, + rvalue* init) +{ + tree inner = global->as_tree (); + /* We need to fold all expressions as much as possible. The code + for a DECL_INITIAL only handles some operations ... + etc addition, minus, 'address of'. See output_addressed_constants() + in varasm.c */ + + tree folded = fold(init->as_tree ()); + DECL_INITIAL (inner) = folded; + gcc_assert (TREE_CONSTANT (DECL_INITIAL (inner))); +} + +playback::rvalue * +playback::context:: +new_ctor (location *loc, + type *type, + const auto_vec *fields, + const auto_vec *rvalues) +{ + tree type_tree = type->as_tree (); + /* Handle empty ctors first. I.e. set everything to "0" */ + if (fields->length () == 0) + return new rvalue (this, build_constructor (type_tree, NULL)); + + int n = fields->length (); + + /* The vec for the constructor node */ + vec *v = NULL; + vec_alloc(v, n); + + int i = 0; + tree field = TYPE_FIELDS (type_tree); + + /* Iterate over the fields, building initializations. */ + for (; field && i < n; field = DECL_CHAIN (field), i++) + { + /* + tree td = DECL_NAME(field); + const char* field_name = IDENTIFIER_POINTER (td); + */ + + /* If the value is NULL, it means we should zero the field */ + if ((*rvalues)[i]) + CONSTRUCTOR_APPEND_ELT(v, field, (*rvalues)[i]->as_tree ()); + else + { + tree zero_cst = build_zero_cst (TREE_TYPE (field)); + CONSTRUCTOR_APPEND_ELT(v, field, zero_cst); + } + } + + /* Any fields remaining are set to 0 */ + for (; field; field = DECL_CHAIN (field)) + { + tree zero_cst = build_zero_cst (TREE_TYPE (field)); + CONSTRUCTOR_APPEND_ELT(v, field, zero_cst); + } + + return new rvalue(this, build_constructor (type_tree, v)); +} + /* Fill 'constructor_elements' with the memory content of 'initializer'. Each element of the initializer is of the size of type T. In use by new_global_initialized.*/ @@ -1109,7 +1174,8 @@ as_truth_value (tree expr, location *loc) if (loc) set_tree_location (typed_zero, loc); - expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero); + expr = fold_build2_loc (UNKNOWN_LOCATION, + NE_EXPR, integer_type_node, expr, typed_zero); if (loc) set_tree_location (expr, loc); @@ -1176,6 +1242,10 @@ new_unary_op (location *loc, inner_result = build1 (inner_op, result_type->as_tree (), node); + + /* Try to fold */ + inner_result = fold (inner_result); + if (loc) set_tree_location (inner_result, loc); @@ -1275,6 +1345,10 @@ new_binary_op (location *loc, result_type->as_tree (), node_a, node_b); + + /* Try to fold the expression */ + inner_expr = fold (inner_expr); + if (loc) set_tree_location (inner_expr, loc); @@ -1326,6 +1400,10 @@ new_comparison (location *loc, boolean_type_node, a->as_tree (), b->as_tree ()); + + /* Try to fold */ + inner_expr = fold (inner_expr); + if (loc) set_tree_location (inner_expr, loc); return new rvalue (this, inner_expr); @@ -1515,6 +1593,7 @@ new_array_access (location *loc, { tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index, NULL_TREE, NULL_TREE); + t_result = fold (t_result); if (loc) set_tree_location (t_result, loc); return new lvalue (this, t_result); @@ -1524,12 +1603,14 @@ new_array_access (location *loc, /* Convert index to an offset in bytes. */ tree t_sizeof = size_in_bytes (t_type_star_ptr); t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index); - tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof); - + tree t_offset = fold_build2_loc (UNKNOWN_LOCATION, + MULT_EXPR, sizetype, t_index, t_sizeof); + /* Locate (ptr + offset). */ - tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset); + tree t_address = fold_build2_loc (UNKNOWN_LOCATION, + POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset); - tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address); + tree t_indirection = fold_build1 (INDIRECT_REF, t_type_star_ptr, t_address); if (loc) { set_tree_location (t_sizeof, loc); @@ -1577,7 +1658,7 @@ new_dereference (tree ptr, gcc_assert (ptr); tree type = TREE_TYPE (TREE_TYPE(ptr)); - tree datum = build1 (INDIRECT_REF, type, ptr); + tree datum = fold_build1 (INDIRECT_REF, type, ptr); if (loc) set_tree_location (datum, loc); return datum; @@ -1731,7 +1812,7 @@ get_address (location *loc) tree t_lvalue = as_tree (); tree t_thistype = TREE_TYPE (t_lvalue); tree t_ptrtype = build_pointer_type (t_thistype); - tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue); + tree ptr = fold_build1 (ADDR_EXPR, t_ptrtype, t_lvalue); if (loc) get_context ()->set_tree_location (ptr, loc); if (mark_addressable (loc)) diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index f670c9e81df..0d062761a06 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -120,6 +120,17 @@ public: const void *initializer, const char *name); + rvalue * + new_ctor (location *log, + type *type, + const auto_vec *fields, + const auto_vec *rvalues); + + + void + global_set_init_rvalue (lvalue* global, + rvalue* init); + template rvalue * new_rvalue_from_const (type *type, diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 9d07062131e..071dd302af9 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -1064,6 +1064,15 @@ recording::context::new_global (recording::location *loc, return result; } +void +recording::context::new_global_init_rvalue (lvalue *global, + rvalue *init) +{ + recording::global_init_rvalue *obj = + new recording::global_init_rvalue (this, global, init); + record (obj); +} + /* Create a recording::memento_of_new_string_literal instance and add it to this context's list of mementos. @@ -1096,12 +1105,26 @@ recording::context::new_rvalue_from_vector (location *loc, return result; } +recording::rvalue * +recording::context::new_ctor (recording::location *loc, + recording::type *type, + int size, + recording::field **fields, + recording::rvalue **rvalues) +{ + recording::rvalue *result = + new ctor (this, loc, type, size, fields, rvalues); + record (result); + return result; +} + /* Create a recording::unary_op instance and add it to this context's list of mementos. Implements the post-error-checking part of gcc_jit_context_new_unary_op. */ + recording::rvalue * recording::context::new_unary_op (recording::location *loc, enum gcc_jit_unary_op op, @@ -5583,6 +5606,150 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r) elements_id); } +void +recording::ctor::visit_children (rvalue_visitor *v) +{ + for (unsigned int i = 0; i < m_values.length (); i++) + v->visit (m_values[i]); +} + +recording::string * +recording::ctor::make_debug_string () +{ + return string::from_printf (m_ctxt, + "ctor"); +} + +void +recording::ctor::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "rvalue"); + r.write (" gcc_jit_rvalue *%s;\n", id); + r.write (" {\n"); /* Open scope for locals */ + + /* Write the array of values */ + r.write (" gcc_jit_rvalue *values[] = {\n"); + for (unsigned int i = 0; i < m_values.length (); i++) + r.write (" %s,\n", r.get_identifier (m_values[i])); + r.write (" };\n"); + /* Write the array of fields */ + r.write (" gcc_jit_field *fields[] = {\n"); + for (unsigned int i = 0; i < m_fields.length (); i++) + r.write (" %s,\n", r.get_identifier (m_fields[i])); + r.write (" };\n"); + + r.write ( +" %s =\n" +" gcc_jit_context_new_constructor (%s,\n" +" %s, /* gcc_jit_location *loc */\n" +" %s, /* gcc_jit_type *type */\n" +" %i, /* int arr_length */\n" +" fields,\n" +" values);\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_loc), + r.get_identifier_as_type (get_type ()), + m_fields.length ()); + + r.write (" }\n"); /* Close scope for locals */ +} + +void +recording::ctor::replay_into (replayer *r) +{ + auto_vec playback_values; + auto_vec playback_fields; + + int n = m_values.length(); + playback_values.reserve (n, false); + playback_fields.reserve (n, false); + + /* Check if we need to sort the fields */ + int is_sorted = 1; + + type *type = get_type (); + compound_type *ct = static_cast(type); + + fields *fields = ct->get_fields (); + int n_fields = fields->length (); + + for (int i = 0; i < n && i < n_fields; i++) + { + field *field_struct = fields->get_field (i); + field *field_ctor = m_fields[i]; + + /* Do the fields have the same type and the same name? */ + if ( + (field_struct->get_type ()-> + accepts_writes_from (field_ctor->get_type())) + && + (0 == strcmp (field_struct->get_name ()->c_str (), + field_ctor->get_name ()->c_str ())) + ) + ; + else + { + is_sorted = 0; + break; + } + } + + if (is_sorted) + { + for (int i = 0; i < n; i++) + playback_values.quick_push (m_values[i]->playback_rvalue ()); + for (int i = 0; i < n; i++) + playback_fields.quick_push (m_fields[i]->playback_field ()); + } + else + { + int n_hits = 0; + for (int i = 0; i < n_fields; i++) + { + field *field_struct = fields->get_field (i); + + int found = 0; + for (int j = 0; j < n; j++) + { + field *field_ctor = m_fields[j]; + + if ( + (field_struct->get_type ()-> + accepts_writes_from (field_ctor->get_type())) + && + (0 == strcmp (field_struct->get_name ()->c_str (), + field_ctor->get_name ()->c_str ())) + ) + { + playback_values.safe_push (m_values[j]->playback_rvalue ()); + playback_fields.safe_push (m_fields[j]->playback_field ()); + found = 1; + n_hits++; + break; + } + } + /* Push null value if not found, to zero the field. */ + if (!found) + { + playback_values.safe_push (NULL); + playback_fields.safe_push (field_struct->playback_field ()); + } + } + /* Verify that we found all the fields specified. */ + if (n_hits != n) + { + /* TODO: Move to new_ctor and raise error. */ + } + + } + + set_playback_obj (r->new_ctor (playback_location (r, m_loc), + get_type ()->playback_type (), + &playback_fields, + &playback_values)); +} + /* The implementation of class gcc::jit::recording::unary_op. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -7556,6 +7723,37 @@ recording::top_level_asm::write_reproducer (reproducer &r) m_asm_stmts->get_debug_string ()); } +void +recording::global_init_rvalue::replay_into (replayer *r) +{ + r->global_set_init_rvalue (m_global->playback_lvalue(), + m_init->playback_rvalue()); +} + +void +recording::global_init_rvalue::write_reproducer (reproducer &r) +{ + r.write ( + " gcc_jit_global_set_initializer_rvalue (%s, /* lvalue *global */\n" + " %s);/* rvalue *init */\n", + r.get_identifier (m_global), + r.get_identifier (m_init)); +} + +void +recording::global_init_rvalue::write_to_dump (dump &d) +{ + d.write ("%s;\n", get_debug_string ()); +} + +recording::string * +recording::global_init_rvalue::make_debug_string () +{ + return string::from_printf(m_ctxt, "%s = {%s}", + m_global->get_debug_string (), + m_init->get_debug_string ()); +} + } // namespace gcc::jit } // namespace gcc diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index d5e0c359a48..e711dce25c8 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -42,7 +42,7 @@ class reproducer; **********************************************************************/ namespace recording { - + playback::location * playback_location (replayer *r, location *loc); @@ -149,6 +149,17 @@ public: type *type, const char *name); + rvalue * + new_ctor (location *loc, + type *type, + int size, + field **fields, + rvalue **values); + + void + new_global_init_rvalue (lvalue *global, + rvalue *init); + template rvalue * new_rvalue_from_const (type *type, @@ -873,6 +884,7 @@ public: {} type * get_type () const { return m_type; } + string * get_name () const { return m_name; } compound_type * get_container () const { return m_container; } void set_container (compound_type *c) { m_container = c; } @@ -1397,7 +1409,14 @@ public: void replay_into (replayer *) FINAL OVERRIDE; - void visit_children (rvalue_visitor *) FINAL OVERRIDE {} + void visit_children (rvalue_visitor *v) FINAL OVERRIDE + { + if (m_init_rvalue) + { + v->visit (m_init_rvalue); + //m_init_rvalue->visit_children (v); + } + } void write_to_dump (dump &d) FINAL OVERRIDE; @@ -1414,6 +1433,12 @@ public: m_initializer_num_bytes = num_bytes; } + void + set_initializer_rvalue (rvalue *rv) + { + m_init_rvalue = rv; + } + private: string * make_debug_string () FINAL OVERRIDE { return m_name; } template @@ -1423,6 +1448,7 @@ private: { return PRECEDENCE_PRIMARY; } + rvalue *m_init_rvalue = 0; private: enum gcc_jit_global_kind m_kind; @@ -1512,6 +1538,44 @@ private: auto_vec m_elements; }; +class ctor : public rvalue +{ +public: + ctor (context *ctxt, + location *loc, + type *type, + int size, + field **fields, + rvalue **values) + : rvalue (ctxt, loc, type) + { + m_fields.reserve (size, false); + m_values.reserve (size, false); + + for (int i = 0; i < size; i++) + { + m_fields.quick_push (fields[i]); + m_values.quick_push (values[i]); + } + } + + void replay_into (replayer *r) FINAL OVERRIDE; + + void visit_children (rvalue_visitor *) FINAL OVERRIDE; + +private: + string * make_debug_string () FINAL OVERRIDE; + void write_reproducer (reproducer &r) FINAL OVERRIDE; + enum precedence get_precedence () const FINAL OVERRIDE + { + return PRECEDENCE_PRIMARY; + } + +private: + auto_vec m_fields; + auto_vec m_values; +}; + class unary_op : public rvalue { public: @@ -2355,6 +2419,24 @@ private: string *m_asm_stmts; }; +class global_init_rvalue : public memento +{ +public: + global_init_rvalue (context *ctxt, lvalue *global, rvalue *init) : + memento(ctxt), m_global (global), m_init (init) {}; + + void write_to_dump (dump &d) FINAL OVERRIDE; + +private: + void replay_into (replayer *r) FINAL OVERRIDE; + string * make_debug_string () FINAL OVERRIDE; + void write_reproducer (reproducer &r) FINAL OVERRIDE; + +private: + lvalue *m_global; + rvalue *m_init; +}; + } // namespace gcc::jit::recording /* Create a recording::memento_of_new_rvalue_from_const instance and add diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 9b4e847c499..fd19c61bd3e 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -1130,6 +1130,38 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt, return (gcc_jit_lvalue *)ctxt->new_global (loc, kind, type, name); } + +extern gcc_jit_rvalue * +gcc_jit_context_new_constructor (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_type *type, + int arr_length, + gcc_jit_field **fields, + gcc_jit_rvalue **values) +{ + int a = 3; + return (gcc_jit_rvalue *)ctxt->new_ctor ( + loc, + type, + arr_length, + (gcc::jit::recording::field **)fields, + (gcc::jit::recording::rvalue **)values); +} + +extern gcc_jit_lvalue * +gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global, + gcc_jit_rvalue *init_value) +{ + RETURN_NULL_IF_FAIL( global, NULL, NULL,"NULL global"); + RETURN_NULL_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL, + "lvalue \"%s\" not a global", + global->get_debug_string ()); + + global->get_context ()->new_global_init_rvalue (global, init_value); + + return global; +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 49e359f420c..be1d9096c4e 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -795,6 +795,18 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt, gcc_jit_type *type, const char *name); +extern gcc_jit_rvalue * +gcc_jit_context_new_constructor (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_type *type, + int arr_length, + gcc_jit_field **fields, + gcc_jit_rvalue **values); + +extern gcc_jit_lvalue * +gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global, + gcc_jit_rvalue *init_value); + #define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer /* Set an initial value for a global, which must be an array of diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 4022dbb6fbc..c5a1afdeacf 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -208,9 +208,11 @@ LIBGCCJIT_ABI_15 { LIBGCCJIT_ABI_16 { global: + gcc_jit_context_new_constructor; gcc_jit_context_new_rvalue_from_complex_double; gcc_jit_context_new_rvalue_from_complex_long_double; - gcc_jit_context_set_bool_enable_complex_types; gcc_jit_context_new_rvalue_from_long_double; gcc_jit_context_new_rvalue_from_long_long; + gcc_jit_context_set_bool_enable_complex_types; + gcc_jit_global_set_initializer_rvalue; } LIBGCCJIT_ABI_15; \ No newline at end of file diff --git a/gcc/testsuite/jit.dg/test-global-init-rvalue.c b/gcc/testsuite/jit.dg/test-global-init-rvalue.c new file mode 100644 index 00000000000..efd77ed2753 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-global-init-rvalue.c @@ -0,0 +1,554 @@ + + +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, + GCC_JIT_TYPE_INT); + gcc_jit_type *pint_type = gcc_jit_type_get_pointer (int_type); + gcc_jit_type *double_type = gcc_jit_context_get_type (ctxt, + GCC_JIT_TYPE_DOUBLE); + gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt, + GCC_JIT_TYPE_FLOAT); + gcc_jit_type *bool_type = gcc_jit_context_get_type (ctxt, + GCC_JIT_TYPE_BOOL); + + /* Make a struct: struct fi { float f; int i;} */ + gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt, + 0, + float_type, + "f"); + gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt, + 0, + int_type, + "i"); + gcc_jit_field *fields[] = {f1, f2}; + + gcc_jit_type *struct_fi_type = + gcc_jit_struct_as_type ( + gcc_jit_context_new_struct_type (ctxt, + 0, + "fi", + 2, + fields)); + + /* Make a struct: + + strict bar { + int ii; + struct fi fi; + float ff; + } + */ + f1 = gcc_jit_context_new_field (ctxt, + 0, + float_type, + "ff"); + f2 = gcc_jit_context_new_field (ctxt, + 0, + int_type, + "ii"); + gcc_jit_field *fi = gcc_jit_context_new_field (ctxt, + 0, + struct_fi_type, + "fi"); + gcc_jit_field *fields2[] = {f1, fi, f2}; + + gcc_jit_type *struct_bar_type = + gcc_jit_struct_as_type ( + gcc_jit_context_new_struct_type (ctxt, + 0, + "bar", + 3, + fields2)); + + /* Make globals initialized with ctors */ + + { /* struct bar bar = {.ii = 4, .ff = 1, .fi = {.i = 3, .f = 2}}; + I.e. nested struct and nested ctors in "wrong" order. + */ + gcc_jit_lvalue *bar = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + struct_bar_type, + "global_struct_bar_1"); + + gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int ( + ctxt, float_type, 2); + gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + + gcc_jit_field *fi_f = gcc_jit_context_new_field (ctxt, + 0, + float_type, + "f"); + gcc_jit_field *fi_i = gcc_jit_context_new_field (ctxt, + 0, + int_type, + "i"); + + gcc_jit_rvalue *vals[] = { ival, fval}; + gcc_jit_field *fields[] = {fi_i, fi_f}; + + gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor + (ctxt, 0, + struct_fi_type, + 2, + fields, + vals); + + ival = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 4); + fval = gcc_jit_context_new_rvalue_from_int ( + ctxt, float_type, 1); + + gcc_jit_field *bar_fi = gcc_jit_context_new_field (ctxt, + 0, + struct_fi_type, + "fi"); + gcc_jit_field *bar_ff = gcc_jit_context_new_field (ctxt, + 0, + float_type, + "ff"); + gcc_jit_field *bar_ii = gcc_jit_context_new_field (ctxt, + 0, + int_type, + "ii"); + + gcc_jit_rvalue *vals2[] = {ival, fval, ctor}; + gcc_jit_field *fields2[] = {bar_ii, bar_ff, bar_fi}; + + gcc_jit_rvalue *ctor_bar = gcc_jit_context_new_constructor + (ctxt, 0, + struct_bar_type, + 3, + fields2, + vals2); + + gcc_jit_global_set_initializer_rvalue (bar, ctor_bar); + } +{ /* struct bar bar = {1, {2, 3}, 4}; + I.e. nested struct and nested ctors in "right" order. + */ + gcc_jit_lvalue *bar = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + struct_bar_type, + "global_struct_bar_2"); + + gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int ( + ctxt, float_type, 2); + gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + + gcc_jit_field *fi_f = gcc_jit_context_new_field (ctxt, + 0, + float_type, + "f"); + gcc_jit_field *fi_i = gcc_jit_context_new_field (ctxt, + 0, + int_type, + "i"); + + gcc_jit_rvalue *vals[] = { fval, ival}; + gcc_jit_field *fields[] = {fi_f, fi_i}; + + gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor + (ctxt, 0, + struct_fi_type, + 2, + fields, + vals); + + ival = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 4); + fval = gcc_jit_context_new_rvalue_from_int ( + ctxt, float_type, 1); + + gcc_jit_field *bar_fi = gcc_jit_context_new_field (ctxt, + 0, + struct_fi_type, + "fi"); + gcc_jit_field *bar_ff = gcc_jit_context_new_field (ctxt, + 0, + float_type, + "ff"); + gcc_jit_field *bar_ii = gcc_jit_context_new_field (ctxt, + 0, + int_type, + "ii"); + + gcc_jit_rvalue *vals2[] = {fval, ctor, ival}; + gcc_jit_field *fields2[] = {bar_ff, bar_fi, bar_ii}; + + gcc_jit_rvalue *ctor_bar = gcc_jit_context_new_constructor + (ctxt, 0, + struct_bar_type, + 3, + fields2, + vals2); + + gcc_jit_global_set_initializer_rvalue (bar, ctor_bar); + } + { /* struct fi foo = {2, 3}; */ + gcc_jit_lvalue *foo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + struct_fi_type, + "global_struct_fi_1"); + + gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int ( + ctxt, float_type, 2); + gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + + gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt, + 0, + float_type, + "f"); + gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt, + 0, + int_type, + "i"); + + gcc_jit_rvalue *vals[] = { fval, ival}; + gcc_jit_field *fields[] = {f1, f2}; + + gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor + (ctxt, 0, + struct_fi_type, + 2, + fields, + vals); + + gcc_jit_global_set_initializer_rvalue (foo, ctor); + } + { /* struct fi foo = {.i = 3, .f = 2}; + + I.e. "wrong" order of fields. */ + gcc_jit_lvalue *foo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + struct_fi_type, + "global_struct_fi_2"); + + gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int ( + ctxt, float_type, 2); + gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + + gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt, + 0, + float_type, + "f"); + gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt, + 0, + int_type, + "i"); + + gcc_jit_rvalue *vals[] = { ival, fval}; + gcc_jit_field *fields[] = {f2, f1}; + + gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor + (ctxt, 0, + struct_fi_type, + 2, + fields, + vals); + gcc_jit_global_set_initializer_rvalue (foo, ctor); + } + { /* struct fi foo = {2 * 2, 3}; */ + gcc_jit_lvalue *foo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + struct_fi_type, + "global_struct_fi_3"); + + gcc_jit_rvalue *fval = gcc_jit_context_new_rvalue_from_int ( + ctxt, float_type, 2); + gcc_jit_rvalue *fval2 = gcc_jit_context_new_rvalue_from_int ( + ctxt, float_type, 2); + gcc_jit_rvalue *ival = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0, + GCC_JIT_BINARY_OP_MULT, + float_type, + fval, + fval2); + + gcc_jit_field *f1 = gcc_jit_context_new_field (ctxt, + 0, + float_type, + "f"); + gcc_jit_field *f2 = gcc_jit_context_new_field (ctxt, + 0, + int_type, + "i"); + + gcc_jit_rvalue *vals[] = { rval_mul, ival}; + gcc_jit_field *fields[] = {f1, f2}; + + gcc_jit_rvalue *ctor = gcc_jit_context_new_constructor + (ctxt, 0, + struct_fi_type, + 2, + fields, + vals); + + gcc_jit_global_set_initializer_rvalue (foo, ctor); + } + { /* int foo = 3; */ + gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_lvalue *foo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + int_type, + "global_int1_3"); + gcc_jit_global_set_initializer_rvalue (foo, + rval); + } + { /* Try the above, but with opposite order of global and literal calls */ + gcc_jit_lvalue *foo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + int_type, + "global_int2_3"); + gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_global_set_initializer_rvalue (foo, + rval); + } + { /* int foo = 3 * (3 + 3) */ + gcc_jit_lvalue *foo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + int_type, + "global_int3_18"); + gcc_jit_rvalue *rval3_0 = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_rvalue *rval3_1 = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_rvalue *rval3_2 = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, 0, + GCC_JIT_BINARY_OP_PLUS, + int_type, + rval3_0, + rval3_1); + gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0, + GCC_JIT_BINARY_OP_MULT, + int_type, + rval_plus, + rval3_2); + + gcc_jit_global_set_initializer_rvalue (foo, + rval_mul); + } + { /* int foo = 3; int *pfoo = &foo; */ + gcc_jit_lvalue *foo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + int_type, + "global_int4_3"); + gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_global_set_initializer_rvalue (foo, + rval); + + gcc_jit_lvalue *pfoo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + pint_type, + "global_pint5"); + gcc_jit_global_set_initializer_rvalue (pfoo, + gcc_jit_lvalue_get_address (foo, 0)); + } + { /* int foo = 3; int *pfoo = &foo + 1; */ + gcc_jit_lvalue *foo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + int_type, + "global_int6_3"); + gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_global_set_initializer_rvalue (foo, + rval); + + gcc_jit_lvalue *pfoo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + pint_type, + "global_pint7"); + gcc_jit_global_set_initializer_rvalue (pfoo, + gcc_jit_lvalue_get_address ( + gcc_jit_context_new_array_access( + ctxt, + 0, + gcc_jit_lvalue_get_address(foo, 0), + gcc_jit_context_one(ctxt, int_type)), + 0)); + } + { + gcc_jit_lvalue *double1 = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + double_type, + "global_double1_3"); + gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int ( + ctxt, double_type, 3); + gcc_jit_global_set_initializer_rvalue (double1, + rval); + } + { /* double foo = 3 * 3 + 3 */ + gcc_jit_lvalue *double1 = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + double_type, + "global_double2_12"); + gcc_jit_rvalue *rval = gcc_jit_context_new_rvalue_from_int ( + ctxt, double_type, 3); + gcc_jit_rvalue *rval_mul = gcc_jit_context_new_binary_op (ctxt, 0, + GCC_JIT_BINARY_OP_MULT, + double_type, + rval, + rval); + gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, 0, + GCC_JIT_BINARY_OP_PLUS, + double_type, + rval_mul, + rval); + gcc_jit_global_set_initializer_rvalue (double1, + rval_plus); + } + { /* bool foo = 3 + 3 <= 6; */ + gcc_jit_lvalue *foo = gcc_jit_context_new_global ( + ctxt, NULL, + GCC_JIT_GLOBAL_EXPORTED, + bool_type, + "global_bool1_1"); + gcc_jit_rvalue *rval3_0 = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_rvalue *rval3_1 = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 3); + gcc_jit_rvalue *rval6 = gcc_jit_context_new_rvalue_from_int ( + ctxt, int_type, 6); + gcc_jit_rvalue *rval_plus = gcc_jit_context_new_binary_op (ctxt, + 0, + GCC_JIT_BINARY_OP_PLUS, + int_type, + rval3_0, + rval3_1); + gcc_jit_rvalue *rval_le = gcc_jit_context_new_comparison (ctxt, + 0, + GCC_JIT_COMPARISON_LE, + rval_plus, + rval6); + + gcc_jit_global_set_initializer_rvalue (foo, + rval_le); + } +} + +struct fi { + float f; + int i; +}; + +struct bar { + float ff; + struct fi fi; + int ii; +}; + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + { + struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_1"); + + CHECK_VALUE (fi->f, 2); + CHECK_VALUE (fi->i, 3); + } + { + struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_2"); + + CHECK_VALUE (fi->f, 2); + CHECK_VALUE (fi->i, 3); + } + { + struct fi *fi = gcc_jit_result_get_global (result, "global_struct_fi_3"); + + CHECK_VALUE (fi->f, 2 * 2); + CHECK_VALUE (fi->i, 3); + } + { + struct bar *bar = gcc_jit_result_get_global (result, "global_struct_bar_1"); + + CHECK_VALUE (bar->ff, 1); + CHECK_VALUE (bar->ii, 4); + CHECK_VALUE (bar->fi.f, 2); + CHECK_VALUE (bar->fi.i, 3); + + bar = gcc_jit_result_get_global (result, "global_struct_bar_2"); + + CHECK_VALUE (bar->ff, 1); + CHECK_VALUE (bar->ii, 4); + CHECK_VALUE (bar->fi.f, 2); + CHECK_VALUE (bar->fi.i, 3); + } + { + int *foo = gcc_jit_result_get_global (result, "global_int1_3"); + + CHECK_VALUE (*foo, 3); + } + { + int *foo = gcc_jit_result_get_global (result, "global_int2_3"); + + CHECK_VALUE (*foo, 3); + } + { + int *foo = gcc_jit_result_get_global (result, "global_int3_18"); + + CHECK_VALUE (*foo, 18); + } + { + int *foo = gcc_jit_result_get_global (result, "global_int4_3"); + int **pfoo = gcc_jit_result_get_global (result, "global_pint5"); + + CHECK_VALUE (*foo, 3); + CHECK_VALUE (foo, *pfoo); + CHECK_VALUE (**pfoo, 3); + } + { + int *foo = gcc_jit_result_get_global (result, "global_int6_3"); + int **pfoo = gcc_jit_result_get_global (result, "global_pint7"); + + CHECK_VALUE (*foo, 3); + CHECK_VALUE (foo + 1, *pfoo); + CHECK_VALUE (*(*pfoo - 1), 3); + } + { + double *foo = gcc_jit_result_get_global (result, "global_double1_3"); + + CHECK_VALUE (*foo, 3); + } + { + double *foo = gcc_jit_result_get_global (result, "global_double2_12"); + + CHECK_VALUE (*foo, 12); + } + { + _Bool *foo = gcc_jit_result_get_global (result, "global_bool1_1"); + + CHECK_VALUE (*foo, 1); + } +} -- 2.30.2