From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 81714 invoked by alias); 10 Aug 2017 00:26:17 -0000 Mailing-List: contact jit-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Subscribe: Sender: jit-owner@gcc.gnu.org Received: (qmail 81668 invoked by uid 89); 10 Aug 2017 00:26:15 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.99.2 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=FINAL, 14036, Structures X-Spam-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 10 Aug 2017 00:26:12 +0000 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 627B32AA5E4; Thu, 10 Aug 2017 00:26:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 627B32AA5E4 Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=dmalcolm@redhat.com Received: from c64.redhat.com (ovpn-112-12.phx2.redhat.com [10.3.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id D833C71C26; Thu, 10 Aug 2017 00:26:08 +0000 (UTC) From: David Malcolm To: Michael Cree Cc: jit@gcc.gnu.org, gcc-patches@gcc.gnu.org, David Malcolm Subject: [committed] jit: add gcc_jit_type_get_vector Date: Sun, 01 Jan 2017 00:00:00 -0000 Message-Id: <1502326873-58234-1-git-send-email-dmalcolm@redhat.com> In-Reply-To: <20170809084227.s23odfpcdyjvrtin@tower> References: <20170809084227.s23odfpcdyjvrtin@tower> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Thu, 10 Aug 2017 00:26:10 +0000 (UTC) X-IsSubscribed: yes X-SW-Source: 2017-q3/txt/msg00005.txt.bz2 On Wed, 2017-08-09 at 20:42 +1200, Michael Cree wrote: > On Mon, Aug 07, 2017 at 10:28:57AM -0400, David Malcolm wrote: > > On Mon, 2017-08-07 at 20:12 +1200, Michael Cree wrote: > > > > Hi Michael > > > > > I am wondering if libgccjit supports vector types, i.e., can one > > > attach attribute __vector_size__ to the base types? There does > > > not > > > seem to be any indication of this in the manual. > > > > Currently this isn't supported. > > > > Is this a blocker for you using libgccjit? > > Yeah, it is. The idea is to generate image processing operators > on the fly. There are opportunities for various optimisations that > can only be decided on at runtime. > > > What would the ideal API > > look like? > > > > Maybe something like: > > > > extern gcc_jit_type * > > gcc_jit_type_get_vector (gcc_jit_type *type, unsigned nunits); > > > > with various requirements (type must be integral/floating point; > > nunits > > must be a power of two). > > I suspect that would do the job nicely. > > Cheers > Michael. I implemented the above (although I switched the 2nd arg to be "size_t num_units"). It looks like you may not need to explicitly use builtins to access machine specific simd intrinsics; for example, on x86_64 when I tried multiplying two of these together for float, with GCC_JIT_BINARY_OP_MULT, which led to this gimple: jit_v4f_mult (const vector(4) * a, const vector(4) * b, vector(4) * c) { initial: _1 = *a; _2 = *b; _3 = _1 * _2; *c = _3; return; } on this x86_64 box it compiled to: movaps (%rdi), %xmm0 mulps (%rsi), %xmm0 movaps %xmm0, (%rdx) ret (i.e. using the "mulps" SIMD instruction). Successfully bootstrapped®rtested on x86_64-pc-linux-gnu; takes jit.sum from 9349 passes to 9759. Committed to trunk as r251018. gcc/jit/ChangeLog: * docs/cp/topics/types.rst (Vector types): New section. * docs/topics/compatibility.rst (LIBGCCJIT_ABI_8): New tag. * docs/topics/types.rst (gcc_jit_context_get_type): Fix typo in example. (Vector types): New section. * docs/_build/texinfo/libgccjit.texi: Regenerate. * jit-playback.c (gcc::jit::playback::type::get_vector): New method. * jit-playback.h (gcc::jit::playback::type::get_vector): New method. * jit-recording.c: In namespace gcc::jit::recording:: (type::get_vector): New method. (memento_of_get_aligned::write_reproducer): Fix typo in leading comment. (memento_of_get_vector::replay_into): New method. (memento_of_get_vector::make_debug_string): New method. (memento_of_get_vector::write_reproducer): New method. * jit-recording.h: In namespace gcc::jit::recording:: (type::get_vector): New method. (class memento_of_get_vector): New class. * libgccjit++.h (gccjit::type::get_vector): New method. * libgccjit.c (gcc_jit_type_get_vector): New public entrypoint. * libgccjit.h (LIBGCCJIT_HAVE_gcc_jit_type_get_vector): New define. (gcc_jit_type_get_vector): New decl. * libgccjit.map (LIBGCCJIT_ABI_8): New ABI tag. gcc/testsuite/ChangeLog: * jit.dg/all-non-failing-tests.h: Add note about test-vector-types.cc. * jit.dg/test-error-gcc_jit_type_get_vector-bad-type.c: New test case. * jit.dg/test-error-gcc_jit_type_get_vector-non-power-of-two.c: New test case. * jit.dg/test-vector-types.cc: New test case. --- gcc/jit/docs/cp/topics/types.rst | 14 ++ gcc/jit/docs/topics/compatibility.rst | 7 + gcc/jit/docs/topics/types.rst | 43 ++++- gcc/jit/jit-playback.c | 11 ++ gcc/jit/jit-playback.h | 1 + gcc/jit/jit-recording.c | 56 ++++++- gcc/jit/jit-recording.h | 26 ++- gcc/jit/libgccjit++.h | 8 + gcc/jit/libgccjit.c | 28 ++++ gcc/jit/libgccjit.h | 15 ++ gcc/jit/libgccjit.map | 5 + gcc/testsuite/jit.dg/all-non-failing-tests.h | 2 + .../test-error-gcc_jit_type_get_vector-bad-type.c | 30 ++++ ...rror-gcc_jit_type_get_vector-non-power-of-two.c | 29 ++++ gcc/testsuite/jit.dg/test-vector-types.cc | 185 +++++++++++++++++++++ 15 files changed, 456 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_vector-bad-type.c create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_vector-non-power-of-two.c create mode 100644 gcc/testsuite/jit.dg/test-vector-types.cc diff --git a/gcc/jit/docs/cp/topics/types.rst b/gcc/jit/docs/cp/topics/types.rst index e85a492..1df896e 100644 --- a/gcc/jit/docs/cp/topics/types.rst +++ b/gcc/jit/docs/cp/topics/types.rst @@ -109,6 +109,20 @@ Pointers, `const`, and `volatile` Param "loc" is optional. +Vector types +------------ + +.. function:: gccjit::type gccjit::type::get_vector (size_t num_units) + + Given type "T", get type: + + .. code-block:: c + + T __attribute__ ((vector_size (sizeof(T) * num_units)) + + T must be integral or floating point; num_units must be a power of two. + + Structures and unions --------------------- diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 5a13653..1d5fbc2 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -149,3 +149,10 @@ entrypoints: ------------------- ``LIBGCCJIT_ABI_7`` covers the addition of :func:`gcc_jit_type_get_aligned` + +.. _LIBGCCJIT_ABI_8: + +``LIBGCCJIT_ABI_8`` +------------------- +``LIBGCCJIT_ABI_8`` covers the addition of +:func:`gcc_jit_type_get_vector` diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst index 119f10e..c279222 100644 --- a/gcc/jit/docs/topics/types.rst +++ b/gcc/jit/docs/topics/types.rst @@ -35,7 +35,7 @@ Types can be created in several ways: .. code-block:: c - gcc_jit_type *int_type = gcc_jit_context_get_type (GCC_JIT_TYPE_INT); + gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); See :func:`gcc_jit_context_get_type` for the available types. @@ -136,6 +136,47 @@ Pointers, `const`, and `volatile` #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_aligned +Vector types +------------ + +.. function:: gcc_jit_type *\ + gcc_jit_type_get_vector (gcc_jit_type *type, \ + size_t num_units) + + Given type "T", get type: + + .. code-block:: c + + T __attribute__ ((vector_size (sizeof(T) * num_units)) + + T must be integral or floating point; num_units must be a power of two. + + This can be used to construct a vector type in which operations + are applied element-wise. The compiler will automatically + use SIMD instructions where possible. See: + https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html + + For example, assuming 4-byte ``ints``, then: + + .. code-block:: c + + typedef int v4si __attribute__ ((vector_size (16))); + + can be obtained using: + + .. code-block:: c + + gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, + GCC_JIT_TYPE_INT); + gcc_jit_type *v4si_type = gcc_jit_type_get_vector (int_type, 4); + + This API entrypoint was added in :ref:`LIBGCCJIT_ABI_8`; you can test + for its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_vector + Structures and unions --------------------- diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 76cc88f..19b6fe2 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -1110,6 +1110,17 @@ get_aligned (size_t alignment_in_bytes) const return new type (t_new_type); } +/* Construct a playback::type instance (wrapping a tree) + for the given vector type. */ + +playback::type * +playback::type:: +get_vector (size_t num_units) const +{ + tree t_new_type = build_vector_type (m_inner, num_units); + return new type (t_new_type); +} + /* Construct a playback::lvalue instance (wrapping a tree) for a field access. */ diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 0a83390..7dc7315 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -392,6 +392,7 @@ public: } type *get_aligned (size_t alignment_in_bytes) const; + type *get_vector (size_t num_units) const; private: tree m_inner; diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 723ddb3..ea4ebb1 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -1988,6 +1988,20 @@ recording::type::get_aligned (size_t alignment_in_bytes) return result; } +/* Given a type, get a vector version of the type. + + Implements the post-error-checking part of + gcc_jit_type_get_vector. */ + +recording::type * +recording::type::get_vector (size_t num_units) +{ + recording::type *result + = new memento_of_get_vector (this, num_units); + m_ctxt->record (result); + return result; +} + const char * recording::type::access_as_type (reproducer &r) { @@ -2457,7 +2471,7 @@ recording::memento_of_get_aligned::make_debug_string () m_alignment_in_bytes); } -/* Implementation of recording::memento::write_reproducer for volatile +/* Implementation of recording::memento::write_reproducer for aligned types. */ void @@ -2471,6 +2485,46 @@ recording::memento_of_get_aligned::write_reproducer (reproducer &r) m_alignment_in_bytes); } +/* The implementation of class gcc::jit::recording::memento_of_get_vector. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_get_vector. */ + +void +recording::memento_of_get_vector::replay_into (replayer *) +{ + set_playback_obj + (m_other_type->playback_type ()->get_vector (m_num_units)); +} + +/* Implementation of recording::memento::make_debug_string for + results of get_vector. */ + +recording::string * +recording::memento_of_get_vector::make_debug_string () +{ + return string::from_printf + (m_ctxt, + "%s __attribute__((vector_size(sizeof (%s) * %zi)))", + m_other_type->get_debug_string (), + m_other_type->get_debug_string (), + m_num_units); +} + +/* Implementation of recording::memento::write_reproducer for volatile + types. */ + +void +recording::memento_of_get_vector::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "type"); + r.write (" gcc_jit_type *%s =\n" + " gcc_jit_type_get_vector (%s, %zi);\n", + id, + r.get_identifier_as_type (m_other_type), + m_num_units); +} + /* The implementation of class gcc::jit::recording::array_type */ /* Implementation of pure virtual hook recording::type::dereference for diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 5faf35e..248765d 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -474,6 +474,7 @@ public: type *get_const (); type *get_volatile (); type *get_aligned (size_t alignment_in_bytes); + type *get_vector (size_t num_units); /* Get the type obtained when dereferencing this type. @@ -600,8 +601,8 @@ private: type *m_other_type; }; -/* A decorated version of a type, for get_const, get_volatile and - get_aligned. */ +/* A decorated version of a type, for get_const, get_volatile, + get_aligned, and get_vector. */ class decorated_type : public type { @@ -683,6 +684,27 @@ private: size_t m_alignment_in_bytes; }; +/* Result of "gcc_jit_type_get_vector". */ +class memento_of_get_vector : public decorated_type +{ +public: + memento_of_get_vector (type *other_type, size_t num_units) + : decorated_type (other_type), + m_num_units (num_units) {} + + /* Strip off the alignment, giving the underlying type. */ + type *unqualified () FINAL OVERRIDE { return m_other_type; } + + void replay_into (replayer *) FINAL OVERRIDE; + +private: + string * make_debug_string () FINAL OVERRIDE; + void write_reproducer (reproducer &r) FINAL OVERRIDE; + +private: + size_t m_num_units; +}; + class array_type : public type { public: diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index ea277f8..a83ccf6 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -333,6 +333,7 @@ namespace gccjit type get_const (); type get_volatile (); type get_aligned (size_t alignment_in_bytes); + type get_vector (size_t num_units); // Shortcuts for getting values of numeric types: rvalue zero (); @@ -1306,6 +1307,13 @@ type::get_aligned (size_t alignment_in_bytes) alignment_in_bytes)); } +inline type +type::get_vector (size_t num_units) +{ + return type (gcc_jit_type_get_vector (get_inner_type (), + num_units)); +} + inline rvalue type::zero () { diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 9b003e3..6e352c6 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -2994,3 +2994,31 @@ gcc_jit_type_get_aligned (gcc_jit_type *type, return (gcc_jit_type *)type->get_aligned (alignment_in_bytes); } + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::get_vector method, in + jit-recording.c. */ + +gcc_jit_type * +gcc_jit_type_get_vector (gcc_jit_type *type, size_t num_units) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + + gcc::jit::recording::context *ctxt = type->m_ctxt; + + JIT_LOG_FUNC (ctxt->get_logger ()); + + RETURN_NULL_IF_FAIL_PRINTF1 + (type->is_int () || type->is_float (), ctxt, NULL, + "type is not integral or floating point: %s", + type->get_debug_string ()); + + RETURN_NULL_IF_FAIL_PRINTF1 + (pow2_or_zerop (num_units), ctxt, NULL, + "num_units not a power of two: %zi", + num_units); + + return (gcc_jit_type *)type->get_vector (num_units); +} diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 898ee98..b863b07 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1403,6 +1403,21 @@ extern gcc_jit_type * gcc_jit_type_get_aligned (gcc_jit_type *type, size_t alignment_in_bytes); +#define LIBGCCJIT_HAVE_gcc_jit_type_get_vector + +/* Given type "T", get type: + + T __attribute__ ((vector_size (sizeof(T) * num_units)) + + T must be integral/floating point; num_units must be a power of two. + + This API entrypoint was added in LIBGCCJIT_ABI_8; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_vector +*/ +extern gcc_jit_type * +gcc_jit_type_get_vector (gcc_jit_type *type, size_t num_units); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 160f4cd..08760e3 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -155,3 +155,8 @@ LIBGCCJIT_ABI_7 { global: gcc_jit_type_get_aligned; } LIBGCCJIT_ABI_6; + +LIBGCCJIT_ABI_8 { + global: + gcc_jit_type_get_vector; +} LIBGCCJIT_ABI_7; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 58e0c30..4af704a 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -228,6 +228,8 @@ of gcc_jit_context_set_bool_allow_unreachable_blocks affects the whole context. */ +/* test-vector-types.cc: We don't use this, since it's C++. */ + /* test-volatile.c */ #define create_code create_code_volatile #define verify_code verify_code_volatile diff --git a/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_vector-bad-type.c b/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_vector-bad-type.c new file mode 100644 index 0000000..59aed33 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_vector-bad-type.c @@ -0,0 +1,30 @@ +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + /* Trigger an API error by passing a bad type. */ + (void)gcc_jit_type_get_vector (void_type, 4); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that the bad API usage prevents the API giving a bogus + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_type_get_vector:" + " type is not integral or floating point: void")); +} + diff --git a/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_vector-non-power-of-two.c b/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_vector-non-power-of-two.c new file mode 100644 index 0000000..aa3bdbd --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_vector-non-power-of-two.c @@ -0,0 +1,29 @@ +#include +#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); + + /* Trigger an API error by passing a bad number of units. */ + (void)gcc_jit_type_get_vector (int_type, 7); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Ensure that the bad API usage prevents the API giving a bogus + result back. */ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error message was emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + ("gcc_jit_type_get_vector:" + " num_units not a power of two: 7")); +} diff --git a/gcc/testsuite/jit.dg/test-vector-types.cc b/gcc/testsuite/jit.dg/test-vector-types.cc new file mode 100644 index 0000000..3389e04 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-vector-types.cc @@ -0,0 +1,185 @@ +#include +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +typedef int v4si __attribute__ ((vector_size (16))); +typedef unsigned int v4ui __attribute__ ((vector_size (16))); +typedef float v4f __attribute__ ((vector_size (16))); + +static void +create_vec_fn (gcc_jit_context *ctxt, const char *fnname, + gcc_jit_type *the_type, enum gcc_jit_binary_op op) +{ + /* Create equivalent to: + + static void + FNNAME (const T *a, const T *b, T *c) + { + *c = *a OP *b; + } + + where T is "the_type" (e.g. v4si). */ + + gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (the_type); + + gcc_jit_type *const_type = gcc_jit_type_get_const (the_type); + gcc_jit_type *ptr_to_const_type = gcc_jit_type_get_pointer (const_type); + + gcc_jit_param *a = + gcc_jit_context_new_param (ctxt, NULL, ptr_to_const_type, "a"); + gcc_jit_param *b = + gcc_jit_context_new_param (ctxt, NULL, ptr_to_const_type, "b"); + gcc_jit_param *c = + gcc_jit_context_new_param (ctxt, NULL, ptr_type, "c"); + + gcc_jit_type *return_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + + gcc_jit_param *params[3] = {a, b, c}; + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + return_type, + fnname, + 3, params, 0); + gcc_jit_block *initial = + gcc_jit_function_new_block (func, "initial"); + + /* (*a OP *b) */ + gcc_jit_rvalue *op_result = + gcc_jit_context_new_binary_op ( + ctxt, NULL, + op, + the_type, + gcc_jit_lvalue_as_rvalue (gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (a), + NULL)), + gcc_jit_lvalue_as_rvalue (gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (b), + NULL))); + /* *c = *a OP *b; */ + gcc_jit_block_add_assignment ( + initial, NULL, + gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (c), NULL), + op_result); + gcc_jit_block_end_with_void_return (initial, NULL); +} + +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 *unsigned_type + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_INT); + gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT); + + gcc_jit_type *v4si_type = gcc_jit_type_get_vector (int_type, 4); + gcc_jit_type *v4ui_type = gcc_jit_type_get_vector (unsigned_type, 4); + gcc_jit_type *v4f_type = gcc_jit_type_get_vector (float_type, 4); + + create_vec_fn (ctxt, "jit_v4si_add", + v4si_type, GCC_JIT_BINARY_OP_PLUS); + create_vec_fn (ctxt, "jit_v4si_sub", + v4si_type, GCC_JIT_BINARY_OP_MINUS); + create_vec_fn (ctxt, "jit_v4si_mult", + v4si_type, GCC_JIT_BINARY_OP_MULT); + create_vec_fn (ctxt, "jit_v4si_div", + v4si_type, GCC_JIT_BINARY_OP_DIVIDE); + + create_vec_fn (ctxt, "jit_v4ui_add", + v4ui_type, GCC_JIT_BINARY_OP_PLUS); + create_vec_fn (ctxt, "jit_v4ui_sub", + v4ui_type, GCC_JIT_BINARY_OP_MINUS); + create_vec_fn (ctxt, "jit_v4ui_mult", + v4ui_type, GCC_JIT_BINARY_OP_MULT); + create_vec_fn (ctxt, "jit_v4ui_div", + v4ui_type, GCC_JIT_BINARY_OP_DIVIDE); + + create_vec_fn (ctxt, "jit_v4f_add", + v4f_type, GCC_JIT_BINARY_OP_PLUS); + create_vec_fn (ctxt, "jit_v4f_sub", + v4f_type, GCC_JIT_BINARY_OP_MINUS); + create_vec_fn (ctxt, "jit_v4f_mult", + v4f_type, GCC_JIT_BINARY_OP_MULT); + create_vec_fn (ctxt, "jit_v4f_div", + v4f_type, GCC_JIT_BINARY_OP_DIVIDE); +} + +template +void +check_add (const T &a, const T &b, const T &c) +{ + for (int i = 0; i < 4; i++) + CHECK_VALUE (c[i], a[i] + b[i]); +} + +template +void +check_sub (const T &a, const T &b, const T &c) +{ + for (int i = 0; i < 4; i++) + CHECK_VALUE (c[i], a[i] - b[i]); +} + +template +void +check_mult (const T &a, const T &b, const T &c) +{ + for (int i = 0; i < 4; i++) + CHECK_VALUE (c[i], a[i] * b[i]); +} + +template +void +check_div (const T &a, const T &b, const T &c) +{ + for (int i = 0; i < 4; i++) + CHECK_VALUE (c[i], a[i] / b[i]); +} + +template +void +verify_vec_code (gcc_jit_context *ctxt, gcc_jit_result *result, + const char *fnname, + void (*check_cb) (const T &a, const T &b, const T &c)) +{ + typedef void (*binop_type) (const T *a, const T *b, T *c); + CHECK_NON_NULL (result); + binop_type fn = + (binop_type)gcc_jit_result_get_code (result, fnname); + CHECK_NON_NULL (fn); + + T a, b, c; + + /* Init. */ + for (int i = 0; i < 4; i++) + { + a[i] = i + 5; + b[i] = (i + 4) * 3; + } + + /* Run jit-compiled code and verify result. */ + fn (&a, &b, &c); + check_cb (a, b, c); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + verify_vec_code (ctxt, result, "jit_v4si_add", check_add); + verify_vec_code (ctxt, result, "jit_v4si_sub", check_sub); + verify_vec_code (ctxt, result, "jit_v4si_mult", check_mult); + verify_vec_code (ctxt, result, "jit_v4si_div", check_div); + + verify_vec_code (ctxt, result, "jit_v4ui_add", check_add); + verify_vec_code (ctxt, result, "jit_v4ui_sub", check_sub); + verify_vec_code (ctxt, result, "jit_v4ui_mult", check_mult); + verify_vec_code (ctxt, result, "jit_v4ui_div", check_div); + + verify_vec_code (ctxt, result, "jit_v4f_add", check_add); + verify_vec_code (ctxt, result, "jit_v4f_sub", check_sub); + verify_vec_code (ctxt, result, "jit_v4f_mult", check_mult); + verify_vec_code (ctxt, result, "jit_v4f_div", check_div); +} -- 1.8.5.3