libgccjit: Add convert vector
gcc/jit/ChangeLog: * docs/topics/compatibility.rst (LIBGCCJIT_ABI_30): New ABI tag. * docs/topics/expressions.rst: Document gcc_jit_context_convert_vector. * jit-playback.cc (convert_vector): New method. * jit-playback.h: New method. * jit-recording.cc (recording::context::new_convert_vector, recording::convert_vector::replay_into, recording::convert_vector::visit_children, recording::convert_vector::make_debug_string, recording::convert_vector::write_reproducer): New methods. * jit-recording.h (class convert_vector): New class. (context::new_convert_vector): New method. * libgccjit.cc (gcc_jit_context_convert_vector): New function. * libgccjit.h (gcc_jit_context_convert_vector): New function. * libgccjit.map: New function. gcc/testsuite/ChangeLog: * jit.dg/all-non-failing-tests.h: New test. * jit.dg/test-convert-vector.c: New test.
This commit is contained in:
parent
b8ac365db7
commit
fe97ac43e0
11 changed files with 286 additions and 0 deletions
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
-------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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},
|
||||
|
|
60
gcc/testsuite/jit.dg/test-convert-vector.c
Normal file
60
gcc/testsuite/jit.dg/test-convert-vector.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#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);
|
||||
}
|
Loading…
Add table
Reference in a new issue