diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 96adc03fed4..33fa763d021 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -411,3 +411,10 @@ on functions and variables: -------------------- ``LIBGCCJIT_ABI_29`` covers the addition of :func:`gcc_jit_global_set_readonly` + +.. _LIBGCCJIT_ABI_30: + +``LIBGCCJIT_ABI_30`` +-------------------- +``LIBGCCJIT_ABI_30`` covers the addition of +:func:`gcc_jit_context_convert_vector` diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 2aabbb82a6b..ca923e7f60c 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -727,6 +727,25 @@ Type-coercion #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_bitcast +.. function:: gcc_jit_rvalue * + gcc_jit_context_convert_vector (gcc_jit_context *ctxt, \ + gcc_jit_location *loc, \ + gcc_jit_rvalue *vector, \ + gcc_jit_type *type) + + Given a vector rvalue, cast it to the type ``type``, doing an element-wise + conversion. + + The number of elements in ``vector`` and ``type`` must match. + The ``type`` must be a vector type. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_30`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_context_convert_vector + Lvalues ------- diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index f0f01648ac1..e32e837f2fe 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -1694,6 +1694,34 @@ new_array_access (location *loc, } } +/* Construct a playback::rvalue instance (wrapping a tree) for a + vector conversion. */ + +playback::rvalue * +playback::context:: +convert_vector (location *loc, + rvalue *vector, + type *type) +{ + gcc_assert (vector); + gcc_assert (type); + + /* For comparison, see: + c/c-common.cc: c_build_vec_convert + */ + + tree t_vector = vector->as_tree (); + + tree t_result = + build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_VEC_CONVERT, + type->as_tree (), 1, t_vector); + + if (loc) + set_tree_location (t_result, loc); + + return new rvalue (this, t_result); +} + /* Construct a tree for a field access. */ tree diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 212f0b2662d..97ad62ccd6a 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -222,6 +222,11 @@ public: rvalue *ptr, rvalue *index); + rvalue * + convert_vector (location *loc, + rvalue *vector, + type *type); + void set_str_option (enum gcc_jit_str_option opt, const char *value); diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index c6b9b3c54bf..7580b625a39 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -1341,6 +1341,23 @@ recording::context::new_array_access (recording::location *loc, return result; } +/* Create a recording::convert_vector instance and add it to this context's list + of mementos. + + Implements the post-error-checking part of + gcc_jit_context_convert_vector. */ + +recording::rvalue * +recording::context::new_convert_vector (recording::location *loc, + recording::rvalue *vector, + recording::type *type) +{ + // TODO: instead have an "internal function" memento? + recording::rvalue *result = new convert_vector (this, loc, vector, type); + record (result); + return result; +} + /* Create a recording::case_ instance and add it to this context's list of mementos. @@ -6572,6 +6589,61 @@ recording::array_access::write_reproducer (reproducer &r) r.get_identifier_as_rvalue (m_index)); } +/* The implementation of class gcc::jit::recording::convert_vector. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::convert_vector. */ + +void +recording::convert_vector::replay_into (replayer *r) +{ + set_playback_obj ( + r->convert_vector (playback_location (r, m_loc), + m_vector->playback_rvalue (), + m_type->playback_type ())); +} + +/* Implementation of pure virtual hook recording::rvalue::visit_children + for recording::convert_vector. */ + +void +recording::convert_vector::visit_children (rvalue_visitor *v) +{ + v->visit (m_vector); +} + +/* Implementation of recording::memento::make_debug_string for + array accesses. */ + +recording::string * +recording::convert_vector::make_debug_string () +{ + enum precedence prec = get_precedence (); + return string::from_printf (m_ctxt, + "(%s)%s", + m_type->get_debug_string (), + m_vector->get_debug_string_parens (prec)); +} + +/* Implementation of recording::memento::write_reproducer for + convert_vector. */ + +void +recording::convert_vector::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "lvalue"); + r.write (" gcc_jit_rvalue *%s = \n" + " gcc_jit_context_convert_vector (%s, /* gcc_jit_context *ctxt */\n" + " %s, /*gcc_jit_location *loc */\n" + " %s, /* gcc_jit_rvalue *vector */\n" + " %s); /* gcc_jit_type *type */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_loc), + r.get_identifier_as_rvalue (m_vector), + r.get_identifier_as_type (m_type)); +} + /* The implementation of class gcc::jit::recording::access_field_of_lvalue. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 07fdcb90773..ec01e62137a 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -230,6 +230,11 @@ public: rvalue *ptr, rvalue *index); + rvalue * + new_convert_vector (location *loc, + rvalue *vector, + type *type); + case_ * new_case (rvalue *min_value, rvalue *max_value, @@ -2004,6 +2009,35 @@ private: rvalue *m_index; }; +class convert_vector : public rvalue +{ +public: + convert_vector (context *ctxt, + location *loc, + rvalue *vector, + type *type) + : rvalue (ctxt, loc, type), + m_vector (vector), + m_type (type) + {} + + void replay_into (replayer *r) final override; + + void visit_children (rvalue_visitor *v) 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_POSTFIX; + } + +private: + rvalue *m_vector; + type *m_type; +}; + class access_field_of_lvalue : public lvalue { public: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index cc36ae96433..664180177fe 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -2556,6 +2556,42 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt, return (gcc_jit_lvalue *)ctxt->new_array_access (loc, ptr, index); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::context::new_convert_vector method in + jit-recording.cc. */ + +gcc_jit_rvalue * +gcc_jit_context_convert_vector (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + /* LOC can be NULL. */ + RETURN_NULL_IF_FAIL (vector, ctxt, loc, "NULL vector"); + RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); + + gcc::jit::recording::vector_type *value_vec_type + = vector->get_type ()->dyn_cast_vector_type (); + RETURN_NULL_IF_FAIL_PRINTF1 (value_vec_type, ctxt, loc, + "%s is not a value of a vector type", + vector->get_debug_string ()); + gcc::jit::recording::vector_type *as_vec_type + = type->dyn_cast_vector_type (); + RETURN_NULL_IF_FAIL_PRINTF1 (as_vec_type, ctxt, loc, + "%s is not a vector type", + type->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF2 ( + as_vec_type->get_num_units () == value_vec_type->get_num_units (), ctxt, + loc, "%s should contain the same number of elements as %s", + vector->get_debug_string (), type->get_debug_string ()); + + return (gcc_jit_rvalue *)ctxt->new_convert_vector (loc, vector, type); +} + /* 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 b1b72774498..bd4606c9868 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1338,6 +1338,16 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt, gcc_jit_rvalue *ptr, gcc_jit_rvalue *index); +#define LIBGCCJIT_HAVE_gcc_jit_context_convert_vector + +/* Given a vector rvalue, cast it to the type ``type``, doing an element-wise + conversion. */ +extern gcc_jit_rvalue * +gcc_jit_context_convert_vector (gcc_jit_context *ctxt, + gcc_jit_location *loc, + gcc_jit_rvalue *vector, + gcc_jit_type *type); + /* Field access is provided separately for both lvalues and rvalues. */ /* Accessing a field of an lvalue of struct type, analogous to: diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 26934ddf8a0..3082725a12b 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -299,3 +299,8 @@ LIBGCCJIT_ABI_29 { global: gcc_jit_global_set_readonly; } LIBGCCJIT_ABI_28; + +LIBGCCJIT_ABI_30 { + global: + gcc_jit_context_convert_vector; +} LIBGCCJIT_ABI_29; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index dfb4dfa98db..32ca70da437 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -148,6 +148,13 @@ /* test-const-attribute.c: This can't be in the testcases array as it needs the `-O3` flag. */ +/* test-convert-vector.c */ +#define create_code create_code_convert_vector +#define verify_code verify_code_convert_vector +#include "test-convert-vector.c" +#undef create_code +#undef verify_code + /* test-debug-strings.c */ #define create_code create_code_debug_strings #define verify_code verify_code_debug_strings @@ -504,6 +511,9 @@ const struct testcase testcases[] = { {"constants", create_code_constants, verify_code_constants}, + {"convert_vector", + create_code_convert_vector, + verify_code_convert_vector}, {"debug_strings", create_code_debug_strings, verify_code_debug_strings}, diff --git a/gcc/testsuite/jit.dg/test-convert-vector.c b/gcc/testsuite/jit.dg/test-convert-vector.c new file mode 100644 index 00000000000..4aba7196c3e --- /dev/null +++ b/gcc/testsuite/jit.dg/test-convert-vector.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + int __attribute__ ((__vector_size__ (8))) convert_vec(double __attribute__ ((__vector_size__ (16))) double_vec) + { + return __builtin_convertvector (double_vec, int __attribute__ ((__vector_size__ (8)))); + } + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_type *int_vector_type = + gcc_jit_type_get_vector (int_type, 2); + gcc_jit_type *double_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); + gcc_jit_type *double_vector_type = + gcc_jit_type_get_vector (double_type, 2); + + /* Build the convert_vec. */ + gcc_jit_param *param = + gcc_jit_context_new_param (ctxt, NULL, double_vector_type, "double_vec"); + gcc_jit_function *convert_vec = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_vector_type, + "convert_vec", + 1, ¶m, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (convert_vec, NULL); + + gcc_jit_lvalue *var = gcc_jit_function_new_local (convert_vec, NULL, double_vector_type, "mem_vec"); + gcc_jit_block_add_assignment (block, NULL, var, gcc_jit_param_as_rvalue (param)); + + gcc_jit_block_end_with_return (block, + NULL, + gcc_jit_context_convert_vector (ctxt, NULL, gcc_jit_lvalue_as_rvalue (var), int_vector_type)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + + typedef int __attribute__ ((__vector_size__ (8))) (*convert_vec)(double __attribute__ ((__vector_size__ (16))) double_vec); + double __attribute__ ((__vector_size__ (16))) double_vec = { 3.2, 7.9 }; + convert_vec func = (convert_vec)gcc_jit_result_get_code (result, "convert_vec"); + int __attribute__ ((__vector_size__ (8))) res = func (double_vec); + int __attribute__ ((__vector_size__ (8))) expected = { 3, 7 }; + CHECK_VECTOR_VALUE (2, res, expected); +}