From 25b386334f22845d7ba1b60658730373eb6ddbb3 Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Fri, 17 Nov 2023 17:23:28 -0500
Subject: [PATCH] libgccjit: Add vector permutation and vector access
operations
gcc/jit/ChangeLog:
PR jit/112602
* docs/topics/compatibility.rst (LIBGCCJIT_ABI_26): New ABI tag.
* docs/topics/expressions.rst: Document
gcc_jit_context_new_rvalue_vector_perm and
gcc_jit_context_new_vector_access.
* jit-playback.cc (playback::context::new_rvalue_vector_perm,
common_mark_addressable_vec,
gnu_vector_type_p,
lvalue_p,
convert_vector_to_array_for_subscript,
new_vector_access): new functions.
* jit-playback.h (new_rvalue_vector_perm, new_vector_access):
New functions.
* jit-recording.cc (recording::context::new_rvalue_vector_perm,
recording::context::new_vector_access,
memento_of_new_rvalue_vector_perm,
recording::memento_of_new_rvalue_vector_perm::replay_into,
recording::memento_of_new_rvalue_vector_perm::visit_children,
recording::memento_of_new_rvalue_vector_perm::make_debug_string,
recording::memento_of_new_rvalue_vector_perm::write_reproducer,
recording::vector_access::replay_into,
recording::vector_access::visit_children,
recording::vector_access::make_debug_string,
recording::vector_access::write_reproducer): New methods.
* jit-recording.h (class memento_of_new_rvalue_vector_perm,
class vector_access): New classes.
* libgccjit.cc (gcc_jit_context_new_vector_access,
gcc_jit_context_new_rvalue_vector_perm): New functions.
* libgccjit.h (gcc_jit_context_new_rvalue_vector_perm,
gcc_jit_context_new_vector_access): New functions.
* libgccjit.map: New functions.
gcc/testsuite/ChangeLog:
PR jit/112602
* jit.dg/all-non-failing-tests.h: New test test-vector-perm.c.
* jit.dg/test-vector-perm.c: New test.
---
gcc/jit/docs/topics/compatibility.rst | 10 ++
gcc/jit/docs/topics/expressions.rst | 53 ++++++
gcc/jit/jit-playback.cc | 150 ++++++++++++++++
gcc/jit/jit-playback.h | 11 ++
gcc/jit/jit-recording.cc | 169 +++++++++++++++++++
gcc/jit/jit-recording.h | 72 ++++++++
gcc/jit/libgccjit.cc | 109 ++++++++++++
gcc/jit/libgccjit.h | 29 ++++
gcc/jit/libgccjit.map | 6 +
gcc/testsuite/jit.dg/all-non-failing-tests.h | 12 +-
gcc/testsuite/jit.dg/test-vector-perm.c | 96 +++++++++++
11 files changed, 716 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/jit.dg/test-vector-perm.c
@@ -378,3 +378,13 @@ alignment of a variable:
--------------------
``LIBGCCJIT_ABI_25`` covers the addition of
:func:`gcc_jit_type_get_restrict`
+
+
+.. _LIBGCCJIT_ABI_26:
+
+``LIBGCCJIT_ABI_26``
+--------------------
+``LIBGCCJIT_ABI_26`` covers the addition of functions to manipulate vectors:
+
+ * :func:`gcc_jit_context_new_rvalue_vector_perm`
+ * :func:`gcc_jit_context_new_vector_access`
@@ -295,6 +295,35 @@ Vector expressions
#ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
+.. function:: gcc_jit_rvalue * \
+ gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt, \
+ gcc_jit_location *loc, \
+ gcc_jit_rvalue *elements1, \
+ gcc_jit_rvalue *elements2, \
+ gcc_jit_rvalue *mask);
+
+ Build a permutation of two vectors.
+
+ "elements1" and "elements2" should have the same type.
+ The length of "mask" and "elements1" should be the same.
+ The element type of "mask" should be integral.
+ The size of the element type of "mask" and "elements1" should be the same.
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_25`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_VECTOR_OPERATIONS
+
+ Analogous to:
+
+ .. code-block:: c
+
+ __builtin_shuffle (elements1, elements2, mask)
+
+ in C.
+
Unary Operations
****************
@@ -1020,3 +1049,27 @@ Field access is provided separately for both lvalues and rvalues.
PTR[INDEX]
in C (or, indeed, to ``PTR + INDEX``).
+
+.. function:: gcc_jit_lvalue *\
+ gcc_jit_context_new_vector_access (gcc_jit_context *ctxt,\
+ gcc_jit_location *loc,\
+ gcc_jit_rvalue *vector,\
+ gcc_jit_rvalue *index)
+
+ Given an rvalue of vector type ``T __attribute__ ((__vector_size__ (SIZE)))``, get the element `T` at
+ the given index.
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_25`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_VECTOR_OPERATIONS
+
+ Analogous to:
+
+ .. code-block:: c
+
+ VECTOR[INDEX]
+
+ in C.
@@ -1011,6 +1011,26 @@ playback::context::new_rvalue_from_vector (location *,
return new rvalue (this, t_ctor);
}
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ vector perm. */
+
+playback::rvalue *
+playback::context::new_rvalue_vector_perm (location *loc,
+ rvalue* elements1,
+ rvalue* elements2,
+ rvalue* mask)
+{
+ tree t_elements1 = elements1->as_tree ();
+ tree t_elements2 = elements2->as_tree ();
+ tree t_mask = mask->as_tree ();
+
+ tree t_vector_perm = build3 (VEC_PERM_EXPR, TREE_TYPE (t_elements1),
+ t_elements1, t_elements2, t_mask);
+ if (loc)
+ set_tree_location (t_vector_perm, loc);
+ return new rvalue (this, t_vector_perm);
+}
+
/* Coerce a tree expression into a boolean tree expression. */
tree
@@ -1527,6 +1547,136 @@ new_array_access (location *loc,
}
}
+/* The following functions come from c-common.h. */
+/* Like c_mark_addressable but don't check register qualifier. */
+void
+common_mark_addressable_vec (tree t)
+{
+ while (handled_component_p (t) || TREE_CODE (t) == C_MAYBE_CONST_EXPR)
+ {
+ t = TREE_OPERAND (t, 0);
+ }
+ if (!VAR_P (t)
+ && TREE_CODE (t) != PARM_DECL
+ && TREE_CODE (t) != COMPOUND_LITERAL_EXPR
+ && TREE_CODE (t) != TARGET_EXPR)
+ return;
+ if (!VAR_P (t) || !DECL_HARD_REGISTER (t))
+ TREE_ADDRESSABLE (t) = 1;
+ if (TREE_CODE (t) == COMPOUND_LITERAL_EXPR)
+ TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (t)) = 1;
+ else if (TREE_CODE (t) == TARGET_EXPR)
+ TREE_ADDRESSABLE (TARGET_EXPR_SLOT (t)) = 1;
+}
+
+/* Return true if TYPE is a vector type that should be subject to the GNU
+ vector extensions (as opposed to a vector type that is used only for
+ the purposes of defining target-specific built-in functions). */
+
+inline bool
+gnu_vector_type_p (const_tree type)
+{
+ return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type);
+}
+
+/* Return nonzero if REF is an lvalue valid for this language.
+ Lvalues can be assigned, unless their type has TYPE_READONLY.
+ Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
+
+bool
+lvalue_p (const_tree ref)
+{
+ const enum tree_code code = TREE_CODE (ref);
+
+ switch (code)
+ {
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case COMPONENT_REF:
+ return lvalue_p (TREE_OPERAND (ref, 0));
+
+ case C_MAYBE_CONST_EXPR:
+ return lvalue_p (TREE_OPERAND (ref, 1));
+
+ case COMPOUND_LITERAL_EXPR:
+ case STRING_CST:
+ return true;
+
+ case MEM_REF:
+ case TARGET_MEM_REF:
+ /* MEM_REFs can appear from -fgimple parsing or folding, so allow them
+ here as well. */
+ case INDIRECT_REF:
+ case ARRAY_REF:
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case ERROR_MARK:
+ return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE);
+
+ case BIND_EXPR:
+ return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE;
+
+ default:
+ return false;
+ }
+}
+
+bool
+convert_vector_to_array_for_subscript (tree *vecp)
+{
+ bool ret = false;
+ if (gnu_vector_type_p (TREE_TYPE (*vecp)))
+ {
+ tree type = TREE_TYPE (*vecp);
+
+ ret = !lvalue_p (*vecp);
+
+ /* We are building an ARRAY_REF so mark the vector as addressable
+ to not run into the gimplifiers premature setting of DECL_GIMPLE_REG_P
+ for function parameters. */
+ /* NOTE: that was the missing piece for making vector access work with
+ optimizations enabled. */
+ common_mark_addressable_vec (*vecp);
+
+ *vecp = build1 (VIEW_CONVERT_EXPR,
+ build_array_type_nelts (TREE_TYPE (type),
+ TYPE_VECTOR_SUBPARTS (type)),
+ *vecp);
+ }
+ return ret;
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+ vector access. */
+
+playback::lvalue *
+playback::context::
+new_vector_access (location *loc,
+ rvalue *vector,
+ rvalue *index)
+{
+ gcc_assert (vector);
+ gcc_assert (index);
+
+ /* For comparison, see:
+ c/c-typeck.cc: build_array_ref
+ */
+
+ tree t_vector = vector->as_tree ();
+ bool non_lvalue = convert_vector_to_array_for_subscript (&t_vector);
+ tree type = TREE_TYPE (TREE_TYPE (t_vector));
+ tree t_result = build4 (ARRAY_REF, type, t_vector, index->as_tree (),
+ NULL_TREE, NULL_TREE);
+ if (non_lvalue)
+ t_result = non_lvalue (t_result);
+
+ if (loc)
+ set_tree_location (t_result, loc);
+ return new lvalue (this, t_result);
+}
+
/* Construct a tree for a field access. */
tree
@@ -147,6 +147,12 @@ public:
type *type,
const auto_vec<rvalue *> &elements);
+ rvalue *
+ new_rvalue_vector_perm (location *loc,
+ rvalue* elements1,
+ rvalue* elements2,
+ rvalue* mask);
+
rvalue *
new_unary_op (location *loc,
enum gcc_jit_unary_op op,
@@ -191,6 +197,11 @@ public:
rvalue *ptr,
rvalue *index);
+ lvalue *
+ new_vector_access (location *loc,
+ rvalue *vector,
+ rvalue *index);
+
void
set_str_option (enum gcc_jit_str_option opt,
const char *value);
@@ -1108,6 +1108,19 @@ recording::context::new_rvalue_from_vector (location *loc,
return result;
}
+recording::rvalue *
+recording::context::new_rvalue_vector_perm (location *loc,
+ rvalue *elements1,
+ rvalue *elements2,
+ rvalue *mask)
+{
+ recording::rvalue *result
+ = new memento_of_new_rvalue_vector_perm (this, loc, elements1, elements2,
+ mask);
+ record (result);
+ return result;
+}
+
recording::rvalue *
recording::context::new_ctor (recording::location *loc,
recording::type *type,
@@ -1309,6 +1322,22 @@ recording::context::new_array_access (recording::location *loc,
return result;
}
+/* Create a recording::vector_access instance and add it to this context's list
+ of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_vector_access. */
+
+recording::lvalue *
+recording::context::new_vector_access (recording::location *loc,
+ recording::rvalue *vector,
+ recording::rvalue *index)
+{
+ recording::lvalue *result = new vector_access (this, loc, vector, index);
+ record (result);
+ return result;
+}
+
/* Create a recording::case_ instance and add it to this context's list
of mementos.
@@ -5437,6 +5466,90 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
elements_id);
}
+/* The implementation of class
+ gcc::jit::recording::memento_of_new_rvalue_vector_perm. */
+
+/* The constructor for
+ gcc::jit::recording::memento_of_new_rvalue_vector_perm. */
+
+recording::memento_of_new_rvalue_vector_perm::
+memento_of_new_rvalue_vector_perm (context *ctxt,
+ location *loc,
+ rvalue *elements1,
+ rvalue *elements2,
+ rvalue *mask)
+: rvalue (ctxt, loc, elements1->get_type ()),
+ m_elements1 (elements1),
+ m_elements2 (elements2),
+ m_mask (mask)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_new_rvalue_vector_perm. */
+
+void
+recording::memento_of_new_rvalue_vector_perm::replay_into (replayer *r)
+{
+ playback::rvalue *playback_elements1 = m_elements1->playback_rvalue ();
+ playback::rvalue *playback_elements2 = m_elements2->playback_rvalue ();
+ playback::rvalue *playback_mask = m_mask->playback_rvalue ();
+
+ set_playback_obj (r->new_rvalue_vector_perm (playback_location (r, m_loc),
+ playback_elements1,
+ playback_elements2,
+ playback_mask));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::memento_of_new_rvalue_from_vector. */
+
+ void
+recording::memento_of_new_rvalue_vector_perm::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_elements1);
+ v->visit (m_elements2);
+ v->visit (m_mask);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ vectors. */
+
+ recording::string *
+recording::memento_of_new_rvalue_vector_perm::make_debug_string ()
+{
+ /* Now build a string. */
+ string *result = string::from_printf (m_ctxt,
+ "shufflevector (%s, %s, %s)",
+ m_elements1->get_debug_string (),
+ m_elements2->get_debug_string (),
+ m_mask->get_debug_string ());
+
+ return result;
+
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ vectors. */
+
+ void
+recording::memento_of_new_rvalue_vector_perm::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "vector");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_rvalue_vector_perm (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue **elements1*/\n"
+ " %s, /* gcc_jit_rvalue **elements2*/\n"
+ " %s); /* gcc_jit_rvalue **mask*/\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_rvalue (m_elements1),
+ r.get_identifier_as_rvalue (m_elements2),
+ r.get_identifier_as_rvalue (m_mask));
+}
+
void
recording::ctor::visit_children (rvalue_visitor *v)
{
@@ -6307,6 +6420,62 @@ recording::array_access::write_reproducer (reproducer &r)
r.get_identifier_as_rvalue (m_index));
}
+/* The implementation of class gcc::jit::recording::vector_access. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::vector_access. */
+
+void
+recording::vector_access::replay_into (replayer *r)
+{
+ set_playback_obj (
+ r->new_vector_access (playback_location (r, m_loc),
+ m_vector->playback_rvalue (),
+ m_index->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::vector_access. */
+
+void
+recording::vector_access::visit_children (rvalue_visitor *v)
+{
+ v->visit (m_vector);
+ v->visit (m_index);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ array accesses. */
+
+recording::string *
+recording::vector_access::make_debug_string ()
+{
+ enum precedence prec = get_precedence ();
+ return string::from_printf (m_ctxt,
+ "%s[%s]",
+ m_vector->get_debug_string_parens (prec),
+ m_index->get_debug_string_parens (prec));
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ vector_access. */
+
+void
+recording::vector_access::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "lvalue");
+ r.write (" gcc_jit_lvalue *%s = \n"
+ " gcc_jit_context_new_vector_access (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /*gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_rvalue *vector */\n"
+ " %s); /* gcc_jit_rvalue *index */\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier_as_rvalue (m_vector),
+ r.get_identifier_as_rvalue (m_index));
+}
+
/* The implementation of class gcc::jit::recording::access_field_of_lvalue. */
/* Implementation of pure virtual hook recording::memento::replay_into
@@ -173,6 +173,12 @@ public:
vector_type *type,
rvalue **elements);
+ rvalue *
+ new_rvalue_vector_perm (location *loc,
+ rvalue *elements1,
+ rvalue *elements2,
+ rvalue *mask);
+
rvalue *
new_unary_op (location *loc,
enum gcc_jit_unary_op op,
@@ -215,6 +221,11 @@ public:
rvalue *ptr,
rvalue *index);
+ lvalue *
+ new_vector_access (location *loc,
+ rvalue *vector,
+ rvalue *index);
+
case_ *
new_case (rvalue *min_value,
rvalue *max_value,
@@ -810,6 +821,10 @@ public:
void replay_into (replayer *) final override;
+ vector_type *dyn_cast_vector_type () final override {
+ return m_other_type->dyn_cast_vector_type ();
+ }
+
private:
string * make_debug_string () final override;
void write_reproducer (reproducer &r) final override;
@@ -1625,6 +1640,33 @@ private:
auto_vec<rvalue *> m_elements;
};
+class memento_of_new_rvalue_vector_perm : public rvalue
+{
+public:
+ memento_of_new_rvalue_vector_perm (context *ctxt,
+ location *loc,
+ rvalue *elements1,
+ rvalue *elements2,
+ rvalue *mask);
+
+ 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:
+ rvalue *m_elements1;
+ rvalue *m_elements2;
+ rvalue *m_mask;
+};
+
class ctor : public rvalue
{
public:
@@ -1907,6 +1949,36 @@ private:
rvalue *m_index;
};
+class vector_access : public lvalue
+{
+public:
+ vector_access (context *ctxt,
+ location *loc,
+ rvalue *vector,
+ rvalue *index)
+ : lvalue (ctxt, loc, vector->get_type ()->dyn_cast_vector_type ()
+ ->get_element_type ()),
+ m_vector (vector),
+ m_index (index)
+ {}
+
+ 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;
+ rvalue *m_index;
+};
+
class access_field_of_lvalue : public lvalue
{
public:
@@ -2437,6 +2437,9 @@ gcc_jit_context_new_cast (gcc_jit_context *ctxt,
/* LOC can be NULL. */
RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+ gcc::jit::recording::vector_type *vector_type = type->dyn_cast_vector_type ();
+ RETURN_NULL_IF_FAIL (vector_type == NULL, ctxt, loc,
+ "cannot cast vector types");
RETURN_NULL_IF_FAIL_PRINTF3 (
is_valid_cast (rvalue->get_type (), type),
ctxt, loc,
@@ -2503,6 +2506,39 @@ 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_vector_access method in
+ jit-recording.cc. */
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_vector_access (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *vector,
+ gcc_jit_rvalue *index)
+{
+ 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 (index, ctxt, loc, "NULL index");
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ vector->get_type ()->dyn_cast_vector_type (),
+ ctxt, loc,
+ "vector: %s (type: %s) is not a vector",
+ vector->get_debug_string (),
+ vector->get_type ()->get_debug_string ());
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ index->get_type ()->is_numeric (),
+ ctxt, loc,
+ "index: %s (type: %s) is not of numeric type",
+ index->get_debug_string (),
+ index->get_type ()->get_debug_string ());
+
+ return (gcc_jit_lvalue *)ctxt->new_vector_access (loc, vector, index);
+}
+
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
@@ -4071,6 +4107,79 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt,
(gcc::jit::recording::rvalue **)elements);
}
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::context::new_rvalue_vector_perm method, in
+ jit-recording.cc. */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *elements1,
+ gcc_jit_rvalue *elements2,
+ gcc_jit_rvalue *mask)
+{
+ RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL ctxt");
+ JIT_LOG_FUNC (ctxt->get_logger ());
+
+ /* LOC can be NULL. */
+
+ gcc::jit::recording::type *elements1_type = elements1->get_type ();
+ gcc::jit::recording::type *elements2_type = elements2->get_type ();
+ RETURN_NULL_IF_FAIL_PRINTF4 (
+ compatible_types (elements1->get_type ()->unqualified (),
+ elements2->get_type ()->unqualified ()),
+ ctxt, loc,
+ "mismatching types for vector perm:"
+ " elements1: %s (type: %s) elements2: %s (type: %s)",
+ elements1->get_debug_string (),
+ elements1_type->get_debug_string (),
+ elements2->get_debug_string (),
+ elements2_type->get_debug_string ());
+
+ gcc::jit::recording::type *mask_type = mask->get_type ();
+ gcc::jit::recording::vector_type *mask_vector_type =
+ mask_type->dyn_cast_vector_type ();
+ gcc::jit::recording::vector_type *elements1_vector_type =
+ elements1_type->dyn_cast_vector_type ();
+
+ size_t mask_len = mask_vector_type->get_num_units ();
+ size_t elements1_len = elements1_vector_type->get_num_units ();
+
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ mask_len == elements1_len,
+ ctxt, loc,
+ "mismatching length for mask:"
+ " elements1 length: %ld mask length: %ld",
+ mask_len,
+ elements1_len);
+
+ gcc::jit::recording::type *mask_element_type =
+ mask_vector_type->get_element_type ();
+
+ RETURN_NULL_IF_FAIL (
+ mask_element_type->is_int (),
+ ctxt, loc,
+ "elements of mask must be of an integer type");
+
+ gcc::jit::recording::type *elements1_element_type =
+ elements1_vector_type->get_element_type ();
+ size_t mask_element_size = mask_element_type->get_size ();
+ size_t elements1_element_size = elements1_element_type->get_size ();
+
+ RETURN_NULL_IF_FAIL_PRINTF2 (
+ mask_element_size == elements1_element_size,
+ ctxt, loc,
+ "mismatching size for mask element type:"
+ " elements1 element type: %ld mask element type: %ld",
+ mask_element_size,
+ elements1_element_size);
+
+ return (gcc_jit_rvalue *)ctxt->new_rvalue_vector_perm (loc, elements1,
+ elements2, mask);
+}
+
/* A mutex around the cached state in parse_basever.
Ideally this would be within parse_basever, but the mutex is only needed
by libgccjit. */
@@ -1301,6 +1301,35 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
gcc_jit_rvalue *ptr,
gcc_jit_rvalue *index);
+/* Build a permutation vector rvalue from an 3 arrays of elements.
+
+ "vec_type" should be a vector type, created using gcc_jit_type_get_vector.
+
+ This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+ presence using
+ #ifdef LIBGCCJIT_HAVE_VECTOR_OPERATIONS
+*/
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *elements1,
+ gcc_jit_rvalue *elements2,
+ gcc_jit_rvalue *mask);
+
+#define LIBGCCJIT_HAVE_VECTOR_OPERATIONS
+
+/* Get the element at INDEX in VECTOR.
+
+ This API entrypoint was added in LIBGCCJIT_ABI_26; you can test for its
+ presence using
+ #ifdef LIBGCCJIT_HAVE_VECTOR_OPERATIONS
+*/
+extern gcc_jit_lvalue *
+gcc_jit_context_new_vector_access (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *vector,
+ gcc_jit_rvalue *index);
+
/* Field access is provided separately for both lvalues and rvalues. */
/* Accessing a field of an lvalue of struct type, analogous to:
@@ -276,3 +276,9 @@ LIBGCCJIT_ABI_25 {
global:
gcc_jit_type_get_restrict;
} LIBGCCJIT_ABI_24;
+
+LIBGCCJIT_ABI_26 {
+ global:
+ gcc_jit_context_new_vector_access;
+ gcc_jit_context_new_rvalue_vector_perm;
+} LIBGCCJIT_ABI_25;
@@ -377,6 +377,13 @@
#undef create_code
#undef verify_code
+/* test-vector-perm.c */
+#define create_code create_code_vector_perm
+#define verify_code verify_code_vector_perm
+#include "test-vector-perm.c"
+#undef create_code
+#undef verify_code
+
/* Now expose the individual testcases as instances of this struct. */
struct testcase
@@ -529,7 +536,10 @@ const struct testcase testcases[] = {
verify_code_version},
{"volatile",
create_code_volatile,
- verify_code_volatile}
+ verify_code_volatile},
+ {"vector_perm",
+ create_code_vector_perm,
+ verify_code_vector_perm},
};
const int num_testcases = (sizeof (testcases) / sizeof (testcases[0]));
new file mode 100644
@@ -0,0 +1,96 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+typedef int v4si __attribute__ ((vector_size (16)));
+
+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 *v4si =
+ gcc_jit_type_get_vector (int_type, 4);
+
+ gcc_jit_function *func_vector =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "vector",
+ 0, NULL,
+ 0);
+
+ gcc_jit_rvalue *elements[4]
+ = { gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 3),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 4),
+ };
+
+ gcc_jit_rvalue *vector
+ = gcc_jit_context_new_rvalue_from_vector (ctxt, NULL, v4si, 4, elements);
+
+ gcc_jit_rvalue *index
+ = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2);
+
+ gcc_jit_block *block_a = gcc_jit_function_new_block (func_vector, NULL);
+ gcc_jit_lvalue *value
+ = gcc_jit_context_new_vector_access (ctxt, NULL, vector, index);
+ gcc_jit_block_end_with_return (block_a, NULL, gcc_jit_lvalue_as_rvalue (value));
+
+ gcc_jit_function *func_vector_perm =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ v4si,
+ "vector_perm",
+ 0, NULL,
+ 0);
+
+ gcc_jit_rvalue *elements2[4]
+ = { gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 5),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 6),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 7),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 8),
+ };
+
+ gcc_jit_rvalue *vector2
+ = gcc_jit_context_new_rvalue_from_vector (ctxt, NULL, v4si, 4, elements2);
+
+ gcc_jit_rvalue *mask_values[4]
+ = { gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 7),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 3),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0),
+ };
+
+ gcc_jit_rvalue *mask
+ = gcc_jit_context_new_rvalue_from_vector (ctxt, NULL, v4si, 4, mask_values);
+
+ gcc_jit_block *block_b = gcc_jit_function_new_block (func_vector_perm, NULL);
+ gcc_jit_rvalue *result = gcc_jit_context_new_rvalue_vector_perm (ctxt, NULL, vector, vector2, mask);
+ gcc_jit_block_end_with_return (block_b, NULL, result);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_NON_NULL (result);
+
+ typedef int (*vector) ();
+ vector fn = (vector)gcc_jit_result_get_code (result, "vector");
+ CHECK_NON_NULL (fn);
+
+ int vector_access = fn ();
+ CHECK_VALUE (vector_access, 3);
+
+ typedef v4si (*vector_perm) ();
+ vector_perm perm_fn = (vector_perm)gcc_jit_result_get_code (result, "vector_perm");
+ CHECK_NON_NULL (perm_fn);
+
+ v4si vector_perm_res = perm_fn ();
+ v4si expected_vec = { 8, 3, 4, 1 };
+ CHECK_VECTOR_VALUE (4, vector_perm_res, expected_vec);
+}
--
2.42.1