From ff47bbec5a833b4470cae7cb636a5fbf31c6432e Mon Sep 17 00:00:00 2001 From: Petter Tomner Date: Tue, 14 Sep 2021 23:51:41 +0200 Subject: [PATCH 1/2] jit: Support for complex types The patch adds support of complex floating point types to libgccjit. A new binary operator 'COMPLEX' is added to create complex values from real values. Aswell as a function to create a complex double literal. To notify users if a binary linking to libgccjit depends on complex types, complex type support most be enabled with a new option function. Signed-off-by: 2021-09-15 Petter Tomner gcc/jit/ * jit-common.h (INNER_BOOL_OPTION_ENABLE_COMPLEX_TYPES): new * jit-playback.c Create imaginary literals, conversions * jit-recording.c Reproducer, debug strings, forwarding * jit-recording.h (float_size_qual): Poll size qualifier of float types (is_complex): Poll if type is complex * libgccjit++.h New entrypoints, see below * libgccjit.c Implementation of new entry points (gcc_jit_context_get_type): Extend range check, validation (valid_binary_op_p): Extend range check (gcc_jit_context_new_binary_op): Validation (gcc_jit_context_new_unary_op): Validation (gcc_jit_context_new_comparison): Validation * libgccjit.h (gcc_jit_context_new_rvalue_from_complex_double): New (GCC_JIT_BINARY_OP_COMPLEX): New (LIBGCCJIT_HAVE_COMPLEX): New (gcc_jit_context_set_bool_enable_complex_types): New * libgccjit.map Added new entrypoints (LIBGCCJIT_ABI_16): New --- 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 ++ 8 files changed, 468 insertions(+), 13 deletions(-) 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 -- 2.30.2