From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 49653 invoked by alias); 31 Mar 2017 20:42:50 -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 49617 invoked by uid 89); 31 Mar 2017 20:42:49 -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=-24.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,T_FILL_THIS_FORM_SHORT,UNSUBSCRIBE_BODY autolearn=ham version=3.3.2 spammy=qualifications, Within, Takes, 9016 X-Spam-Status: No, score=-24.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,T_FILL_THIS_FORM_SHORT,UNSUBSCRIBE_BODY 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 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 81E7E3DF836 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=dmalcolm@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 81E7E3DF836 From: David Malcolm To: Florian Weimer Cc: =?UTF-8?q?=EC=A0=95=EC=9D=B8=EB=B0=B0=28Inbae=20Jeong=29?= , jit@gcc.gnu.org, gcc-patches@gcc.gnu.org, David Malcolm Subject: [PATCH] Add gcc_jit_type_get_aligned Date: Sun, 01 Jan 2017 00:00:00 -0000 Message-Id: <1490994792-6645-1-git-send-email-dmalcolm@redhat.com> In-Reply-To: <87y3vmse4n.fsf@mid.deneb.enyo.de> References: <87y3vmse4n.fsf@mid.deneb.enyo.de> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Fri, 31 Mar 2017 20:42:45 +0000 (UTC) X-SW-Source: 2017-q1/txt/msg00025.txt.bz2 On Thu, 2017-03-30 at 22:28 +0200, Florian Weimer wrote: > * David Malcolm: > > > Here's a work-in-progress implementation of the idea, adding this > > entrypoint to the API: > > > > extern gcc_jit_type * > > gcc_jit_type_get_aligned (gcc_jit_type *type, > > unsigned int alignment_in_bytes); > > Should be size_t, not unsigned int. A 2**31 alignment isn't as > ridiculous as it might seem. x86-64 already has a 2**30 alignment > requirement in some contexts. Thanks; fixed in this version. Here's a completed version of the patch. It also implements the missing C++ binding gccjit::type::get_const, needed by a test case. Successfully bootstrapped®rtested on x86_64-pc-linux-gnu. Takes jit.sum from 8609 to 9349 PASS results. Release managers: is it acceptable to commit this to trunk in stage 4? It purely touches jit-related code/testcases, but I appreciate it's very late to be adding features. Otherwise I'll commit it in the next stage 1. gcc/jit/ChangeLog: * docs/cp/topics/types.rst (gccjit::type::get_const): Remove comment. (gccjit::type::get_aligned): Add. * docs/topics/compatibility.rst: Add LIBGCCJIT_ABI_7. * docs/topics/types.rst: Add gcc_jit_type_get_aligned. * jit-playback.c (gcc::jit::playback::type::get_aligned): New method. * jit-playback.h (gcc::jit::playback::type::get_aligned): New method. * jit-recording.c: Within namespace gcc::jit::recording... (type::get_aligned): New method. (memento_of_get_aligned::replay_into): New method. (memento_of_get_aligned::make_debug_string): New method. (memento_of_get_aligned::write_reproducer): New method. * jit-recording.h: Within namespace gcc::jit::recording... (type::get_aligned): New method. (type::accepts_writes_from): Strip off qualifications from this when comparing pointer equality. (decorated_type): New subclass of type, subsuming the commonality between memento_of_get_const and memento_of_get_volatile. (memento_of_get_const): Make a subclass of decorated_type, rather than type. (memento_of_get_volatile): Likewise. (memento_of_get_aligned): Likewise. * libgccjit++.h: Within namespace gccjit... (type::get_const): New method. (type::get_aligned): New method. * libgccjit.c (gcc_jit_type_get_aligned): New function. * libgccjit.h (gcc_jit_type_get_aligned): New decl. * libgccjit.map (LIBGCCJIT_ABI_7): New (gcc_jit_type_get_aligned): Add. gcc/testsuite/ChangeLog: * jit.dg/all-non-failing-tests.h: Add test-alignment.c. * jit.dg/test-alignment.c: New test case. * jit.dg/test-alignment.cc: New test case. * jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.c: New test case. --- gcc/jit/docs/cp/topics/types.rst | 12 +- gcc/jit/docs/topics/compatibility.rst | 7 + gcc/jit/docs/topics/types.rst | 19 ++ gcc/jit/jit-playback.c | 15 ++ gcc/jit/jit-playback.h | 2 + gcc/jit/jit-recording.c | 52 +++++ gcc/jit/jit-recording.h | 68 +++--- gcc/jit/libgccjit++.h | 15 ++ gcc/jit/libgccjit.c | 24 +++ gcc/jit/libgccjit.h | 16 ++ gcc/jit/libgccjit.map | 5 + gcc/testsuite/jit.dg/all-non-failing-tests.h | 10 + gcc/testsuite/jit.dg/test-alignment.c | 232 +++++++++++++++++++++ gcc/testsuite/jit.dg/test-alignment.cc | 176 ++++++++++++++++ ...ror-gcc_jit_type_get_aligned-non-power-of-two.c | 30 +++ 15 files changed, 657 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-alignment.c create mode 100644 gcc/testsuite/jit.dg/test-alignment.cc create mode 100644 gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.c diff --git a/gcc/jit/docs/cp/topics/types.rst b/gcc/jit/docs/cp/topics/types.rst index 453f1d3..e85a492 100644 --- a/gcc/jit/docs/cp/topics/types.rst +++ b/gcc/jit/docs/cp/topics/types.rst @@ -82,8 +82,6 @@ Pointers, `const`, and `volatile` Given type "T", get type "T*". -.. FIXME: get_const doesn't seem to exist - .. function:: gccjit::type gccjit::type::get_const () Given type "T", get type "const T". @@ -92,6 +90,16 @@ Pointers, `const`, and `volatile` Given type "T", get type "volatile T". +.. function:: gccjit::type gccjit::type::get_aligned (size_t alignment_in_bytes) + + Given type "T", get type: + + .. code-block:: c + + T __attribute__ ((aligned (ALIGNMENT_IN_BYTES))) + + The alignment must be a power of two. + .. function:: gccjit::type \ gccjit::context::new_array_type (gccjit::type element_type, \ int num_elements, \ diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 4aff425..5a13653 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -142,3 +142,10 @@ entrypoints: ------------------- ``LIBGCCJIT_ABI_6`` covers the addition of :func:`gcc_jit_rvalue_set_bool_require_tail_call` + +.. _LIBGCCJIT_ABI_7: + +``LIBGCCJIT_ABI_7`` +------------------- +``LIBGCCJIT_ABI_7`` covers the addition of +:func:`gcc_jit_type_get_aligned` diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst index 9a1b879..119f10e 100644 --- a/gcc/jit/docs/topics/types.rst +++ b/gcc/jit/docs/topics/types.rst @@ -117,6 +117,25 @@ Pointers, `const`, and `volatile` Given type "T", get type "T[N]" (for a constant N). +.. function:: gcc_jit_type *\ + gcc_jit_type_get_aligned (gcc_jit_type *type, \ + size_t alignment_in_bytes) + + Given type "T", get type: + + .. code-block:: c + + T __attribute__ ((aligned (ALIGNMENT_IN_BYTES))) + + The alignment must be a power of two. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_7`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_aligned + Structures and unions --------------------- diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index c0f10c9..76cc88f 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -1095,6 +1095,21 @@ new_dereference (tree ptr, return datum; } +/* Construct a playback::type instance (wrapping a tree) + with the given alignment. */ + +playback::type * +playback::type:: +get_aligned (size_t alignment_in_bytes) const +{ + tree t_new_type = build_variant_type_copy (m_inner); + + SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT); + TYPE_USER_ALIGN (t_new_type) = 1; + + 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 5c8555c..0a83390 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -391,6 +391,8 @@ public: return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE)); } + type *get_aligned (size_t alignment_in_bytes) const; + private: tree m_inner; }; diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index e356c14..723ddb3 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -1974,6 +1974,20 @@ recording::type::get_volatile () return result; } +/* Given a type, get an aligned version of the type. + + Implements the post-error-checking part of + gcc_jit_type_get_aligned. */ + +recording::type * +recording::type::get_aligned (size_t alignment_in_bytes) +{ + recording::type *result + = new memento_of_get_aligned (this, alignment_in_bytes); + m_ctxt->record (result); + return result; +} + const char * recording::type::access_as_type (reproducer &r) { @@ -2419,6 +2433,44 @@ recording::memento_of_get_volatile::write_reproducer (reproducer &r) r.get_identifier_as_type (m_other_type)); } +/* The implementation of class gcc::jit::recording::memento_of_get_aligned. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_get_aligned. */ + +void +recording::memento_of_get_aligned::replay_into (replayer *) +{ + set_playback_obj + (m_other_type->playback_type ()->get_aligned (m_alignment_in_bytes)); +} + +/* Implementation of recording::memento::make_debug_string for + results of get_aligned. */ + +recording::string * +recording::memento_of_get_aligned::make_debug_string () +{ + return string::from_printf (m_ctxt, + "%s __attribute__((aligned(%zi)))", + m_other_type->get_debug_string (), + m_alignment_in_bytes); +} + +/* Implementation of recording::memento::write_reproducer for volatile + types. */ + +void +recording::memento_of_get_aligned::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "type"); + r.write (" gcc_jit_type *%s =\n" + " gcc_jit_type_get_aligned (%s, %zi);\n", + id, + r.get_identifier_as_type (m_other_type), + m_alignment_in_bytes); +} + /* 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 8e5bd52..5faf35e 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -473,6 +473,7 @@ public: type *get_pointer (); type *get_const (); type *get_volatile (); + type *get_aligned (size_t alignment_in_bytes); /* Get the type obtained when dereferencing this type. @@ -489,7 +490,7 @@ public: virtual bool accepts_writes_from (type *rtype) { gcc_assert (rtype); - return this == rtype->unqualified (); + return this->unqualified () == rtype->unqualified (); } /* Strip off "const" etc */ @@ -599,16 +600,35 @@ private: type *m_other_type; }; -/* Result of "gcc_jit_type_get_const". */ -class memento_of_get_const : public type +/* A decorated version of a type, for get_const, get_volatile and + get_aligned. */ + +class decorated_type : public type { public: - memento_of_get_const (type *other_type) + decorated_type (type *other_type) : type (other_type->m_ctxt), m_other_type (other_type) {} type *dereference () FINAL OVERRIDE { return m_other_type->dereference (); } + 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 (); } + type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); } + type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); } + +protected: + type *m_other_type; +}; + +/* Result of "gcc_jit_type_get_const". */ +class memento_of_get_const : public decorated_type +{ +public: + memento_of_get_const (type *other_type) + : decorated_type (other_type) {} + bool accepts_writes_from (type */*rtype*/) FINAL OVERRIDE { /* Can't write to a "const". */ @@ -618,40 +638,40 @@ public: /* Strip off the "const", giving the underlying type. */ type *unqualified () FINAL OVERRIDE { return m_other_type; } - 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 (); } - type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); } - type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); } - void replay_into (replayer *) FINAL OVERRIDE; private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; - -private: - type *m_other_type; }; /* Result of "gcc_jit_type_get_volatile". */ -class memento_of_get_volatile : public type +class memento_of_get_volatile : public decorated_type { public: memento_of_get_volatile (type *other_type) - : type (other_type->m_ctxt), - m_other_type (other_type) {} - - type *dereference () FINAL OVERRIDE { return m_other_type->dereference (); } + : decorated_type (other_type) {} /* Strip off the "volatile", giving the underlying type. */ type *unqualified () FINAL OVERRIDE { return m_other_type; } - 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 (); } - type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); } - type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); } + void replay_into (replayer *) FINAL OVERRIDE; + +private: + string * make_debug_string () FINAL OVERRIDE; + void write_reproducer (reproducer &r) FINAL OVERRIDE; +}; + +/* Result of "gcc_jit_type_get_aligned". */ +class memento_of_get_aligned : public decorated_type +{ +public: + memento_of_get_aligned (type *other_type, size_t alignment_in_bytes) + : decorated_type (other_type), + m_alignment_in_bytes (alignment_in_bytes) {} + + /* Strip off the alignment, giving the underlying type. */ + type *unqualified () FINAL OVERRIDE { return m_other_type; } void replay_into (replayer *) FINAL OVERRIDE; @@ -660,7 +680,7 @@ private: void write_reproducer (reproducer &r) FINAL OVERRIDE; private: - type *m_other_type; + size_t m_alignment_in_bytes; }; class array_type : public type diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 8dc2112..ea277f8 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -330,7 +330,9 @@ namespace gccjit gcc_jit_type *get_inner_type () const; type get_pointer (); + type get_const (); type get_volatile (); + type get_aligned (size_t alignment_in_bytes); // Shortcuts for getting values of numeric types: rvalue zero (); @@ -1286,11 +1288,24 @@ type::get_pointer () } inline type +type::get_const () +{ + return type (gcc_jit_type_get_const (get_inner_type ())); +} + +inline type type::get_volatile () { return type (gcc_jit_type_get_volatile (get_inner_type ())); } +inline type +type::get_aligned (size_t alignment_in_bytes) +{ + return type (gcc_jit_type_get_aligned (get_inner_type (), + alignment_in_bytes)); +} + inline rvalue type::zero () { diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index b5e72f4..9b003e3 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -2970,3 +2970,27 @@ gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue *rvalue, call->set_require_tail_call (require_tail_call); } + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::get_aligned method, in + jit-recording.c. */ + +gcc_jit_type * +gcc_jit_type_get_aligned (gcc_jit_type *type, + size_t alignment_in_bytes) +{ + 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 + (pow2_or_zerop (alignment_in_bytes), ctxt, NULL, + "alignment not a power of two: %zi", + alignment_in_bytes); + + return (gcc_jit_type *)type->get_aligned (alignment_in_bytes); +} diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 8965093..898ee98 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1387,6 +1387,22 @@ extern void gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue *call, int require_tail_call); +#define LIBGCCJIT_HAVE_gcc_jit_type_get_aligned + +/* Given type "T", get type: + + T __attribute__ ((aligned (ALIGNMENT_IN_BYTES))) + + The alignment must be a power of two. + + This API entrypoint was added in LIBGCCJIT_ABI_7; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_aligned +*/ +extern gcc_jit_type * +gcc_jit_type_get_aligned (gcc_jit_type *type, + size_t alignment_in_bytes); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 80a273f..160f4cd 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -150,3 +150,8 @@ LIBGCCJIT_ABI_6 { global: gcc_jit_rvalue_set_bool_require_tail_call; } LIBGCCJIT_ABI_5; + +LIBGCCJIT_ABI_7 { + global: + gcc_jit_type_get_aligned; +} LIBGCCJIT_ABI_6; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 3e2b3b9..58e0c30 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -22,6 +22,13 @@ #undef create_code #undef verify_code +/* test-alignment.c */ +#define create_code create_code_alignment +#define verify_code verify_code_alignment +#include "test-alignment.c" +#undef create_code +#undef verify_code + /* test-arith-overflow.c */ #define create_code create_code_arith_overflow #define verify_code verify_code_arith_overflow @@ -246,6 +253,9 @@ const struct testcase testcases[] = { {"accessing_union", create_code_accessing_union, verify_code_accessing_union}, + {"alignment", + create_code_alignment, + verify_code_alignment}, {"arith_overflow", create_code_arith_overflow, verify_code_arith_overflow}, diff --git a/gcc/testsuite/jit.dg/test-alignment.c b/gcc/testsuite/jit.dg/test-alignment.c new file mode 100644 index 0000000..686d981 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-alignment.c @@ -0,0 +1,232 @@ +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +struct s2 +{ + char x __attribute__ ((aligned (2))); + char y __attribute__ ((aligned (2))); +}; + +struct s4 +{ + char x __attribute__ ((aligned (4))); + char y __attribute__ ((aligned (4))); +}; + +struct s8 +{ + char x __attribute__ ((aligned (8))); + char y __attribute__ ((aligned (8))); +}; + +struct s16 +{ + char x __attribute__ ((aligned (16))); + char y __attribute__ ((aligned (16))); +}; + +struct s32 +{ + char x __attribute__ ((aligned (32))); + char y __attribute__ ((aligned (32))); +}; + +struct s64 +{ + char x __attribute__ ((aligned (64))); + char y __attribute__ ((aligned (64))); +}; + +struct s128 +{ + char x __attribute__ ((aligned (128))); + char y __attribute__ ((aligned (128))); +}; + +static void +create_aligned_code (gcc_jit_context *ctxt, const char *struct_name, + unsigned int alignment, const char *reader_fn_name, + const char *writer_fn_name) +{ + /* Let's try to inject the equivalent of: + + char + READER_FN_NAME (const struct STRUCT_NAME *f) + { + return f->x * f->y; + } + + char + WRITER_FN_NAME (struct STRUCT_NAME *g) + { + g->x = 5; + g->y = 7; + return READER_FN_NAME (g); + } + */ + gcc_jit_type *char_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR); + gcc_jit_type *aligned_char_type = + gcc_jit_type_get_aligned (char_type, alignment); + gcc_jit_field *x = + gcc_jit_context_new_field (ctxt, + NULL, + aligned_char_type, + "x"); + gcc_jit_field *y = + gcc_jit_context_new_field (ctxt, + NULL, + aligned_char_type, + "y"); + gcc_jit_field *fields[] = {x, y}; + gcc_jit_type *struct_type = + gcc_jit_struct_as_type ( + gcc_jit_context_new_struct_type (ctxt, NULL, struct_name, 2, fields)); + gcc_jit_type *const_struct_type = gcc_jit_type_get_const (struct_type); + gcc_jit_type *const_ptr_type = gcc_jit_type_get_pointer (const_struct_type); + + /* Build the reader fn. */ + gcc_jit_param *param_f = + gcc_jit_context_new_param (ctxt, NULL, const_ptr_type, "f"); + gcc_jit_function *fn_test_reading = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + char_type, + reader_fn_name, + 1, ¶m_f, + 0); + + /* return f->x * f->y; */ + gcc_jit_block *reading_block = gcc_jit_function_new_block (fn_test_reading, NULL); + gcc_jit_block_end_with_return ( + reading_block, + NULL, + gcc_jit_context_new_binary_op ( + ctxt, NULL, + GCC_JIT_BINARY_OP_MULT, + char_type, + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_f), + NULL, + x)), + gcc_jit_lvalue_as_rvalue ( + gcc_jit_rvalue_dereference_field ( + gcc_jit_param_as_rvalue (param_f), + NULL, + y)))); + + /* Build the writer fn. */ + gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (struct_type); + gcc_jit_param *param_g = + gcc_jit_context_new_param (ctxt, NULL, ptr_type, "g"); + gcc_jit_function *fn_test_writing = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + char_type, + writer_fn_name, + 1, ¶m_g, + 0); + + /* g->x = 5; */ + gcc_jit_block *writing_block = gcc_jit_function_new_block (fn_test_writing, NULL); + gcc_jit_block_add_assignment ( + writing_block, NULL, + gcc_jit_rvalue_dereference_field (gcc_jit_param_as_rvalue (param_g), + NULL, x), + gcc_jit_context_new_rvalue_from_int (ctxt, char_type, 5)); + + /* g->y = 7; */ + gcc_jit_block_add_assignment ( + writing_block, NULL, + gcc_jit_rvalue_dereference_field (gcc_jit_param_as_rvalue (param_g), + NULL, y), + gcc_jit_context_new_rvalue_from_int (ctxt, char_type, 7)); + + /* return READER_FN_NAME (g); */ + gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_g); + gcc_jit_block_end_with_return ( + writing_block, + NULL, + gcc_jit_context_new_call ( + ctxt, NULL, + fn_test_reading, + 1, &arg)); +} + +/* Implement a verifier function for a given struct. */ + +#define IMPL_VERIFY_ALIGNED_CODE(TYPENAME) \ + static void \ + verify_aligned_code_ ##TYPENAME (gcc_jit_context *ctxt, \ + gcc_jit_result *result, \ + const char *writer_fn_name) \ + { \ + typedef int (*fn_type) (struct TYPENAME *); \ + CHECK_NON_NULL (result); \ + \ + struct TYPENAME tmp; \ + memset (&tmp, 0xac, sizeof (tmp)); \ + \ + fn_type test_writing = \ + (fn_type)gcc_jit_result_get_code (result, writer_fn_name); \ + CHECK_NON_NULL (test_writing); \ + \ + /* Verify that the code correctly returns the product of the fields. */ \ + CHECK_VALUE (test_writing (&tmp), 35); \ + \ + /* Verify the we can read the values of the fields, and thus that the \ + struct layout agrees with that of the C frontend. */ \ + CHECK_VALUE (tmp.x, 5); \ + CHECK_VALUE (tmp.y, 7); \ + } + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + create_aligned_code (ctxt, "s2", 2, "test_aligned_reading_s2", + "test_aligned_writing_s2"); + create_aligned_code (ctxt, "s4", 4, "test_aligned_reading_s4", + "test_aligned_writing_s4"); + create_aligned_code (ctxt, "s8", 8, "test_aligned_reading_s8", + "test_aligned_writing_s8"); + create_aligned_code (ctxt, "s16", 16, "test_aligned_reading_s16", + "test_aligned_writing_s16"); + create_aligned_code (ctxt, "s32", 32, "test_aligned_reading_s32", + "test_aligned_writing_s32"); + create_aligned_code (ctxt, "s64", 64, "test_aligned_reading_s64", + "test_aligned_writing_s64"); + create_aligned_code (ctxt, "s128", 128, "test_aligned_reading_s128", + "test_aligned_writing_s128"); +} + +IMPL_VERIFY_ALIGNED_CODE(s2) +IMPL_VERIFY_ALIGNED_CODE(s4) +IMPL_VERIFY_ALIGNED_CODE(s8) +IMPL_VERIFY_ALIGNED_CODE(s16) +IMPL_VERIFY_ALIGNED_CODE(s32) +IMPL_VERIFY_ALIGNED_CODE(s64) +IMPL_VERIFY_ALIGNED_CODE(s128) + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + verify_aligned_code_s2 (ctxt, result, + "test_aligned_writing_s2"); + verify_aligned_code_s4 (ctxt, result, + "test_aligned_writing_s4"); + verify_aligned_code_s8 (ctxt, result, + "test_aligned_writing_s8"); + verify_aligned_code_s16 (ctxt, result, + "test_aligned_writing_s16"); + verify_aligned_code_s32 (ctxt, result, + "test_aligned_writing_s32"); + verify_aligned_code_s64 (ctxt, result, + "test_aligned_writing_s64"); + verify_aligned_code_s128 (ctxt, result, + "test_aligned_writing_s128"); +} diff --git a/gcc/testsuite/jit.dg/test-alignment.cc b/gcc/testsuite/jit.dg/test-alignment.cc new file mode 100644 index 0000000..3e99209 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-alignment.cc @@ -0,0 +1,176 @@ +#include +#include + +#include "libgccjit++.h" + +#include "harness.h" + +struct s2 +{ + char x __attribute__ ((aligned (2))); + char y __attribute__ ((aligned (2))); +}; + +struct s4 +{ + char x __attribute__ ((aligned (4))); + char y __attribute__ ((aligned (4))); +}; + +struct s8 +{ + char x __attribute__ ((aligned (8))); + char y __attribute__ ((aligned (8))); +}; + +struct s16 +{ + char x __attribute__ ((aligned (16))); + char y __attribute__ ((aligned (16))); +}; + +struct s32 +{ + char x __attribute__ ((aligned (32))); + char y __attribute__ ((aligned (32))); +}; + +struct s64 +{ + char x __attribute__ ((aligned (64))); + char y __attribute__ ((aligned (64))); +}; + +struct s128 +{ + char x __attribute__ ((aligned (128))); + char y __attribute__ ((aligned (128))); +}; + +static void +create_aligned_code (gcc_jit_context *c_ctxt, const char *struct_name, + unsigned int alignment, const char *reader_fn_name, + const char *writer_fn_name) +{ + /* Let's try to inject the equivalent of: + + char + READER_FN_NAME (const struct STRUCT_NAME *f) + { + return f->x * f->y; + } + + char + WRITER_FN_NAME (struct STRUCT_NAME *g) + { + g->x = 5; + g->y = 7; + return READER_FN_NAME (g); + } + */ + gccjit::context ctxt (c_ctxt); + gccjit::type char_type = ctxt.get_type (GCC_JIT_TYPE_CHAR); + gccjit::type aligned_char_type = char_type.get_aligned (alignment); + gccjit::field x = ctxt.new_field (aligned_char_type, "x"); + gccjit::field y = ctxt.new_field (aligned_char_type, "y"); + std::vector fields = {x, y}; + gccjit::type struct_type = ctxt.new_struct_type (struct_name, fields); + gccjit::type const_struct_type = struct_type.get_const (); + gccjit::type const_ptr_type = const_struct_type.get_pointer (); + + /* Build the reader fn. */ + gccjit::param param_f = ctxt.new_param (const_ptr_type, "f"); + std::vector params = {param_f}; + gccjit::function fn_test_reading + = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + char_type, + reader_fn_name, + params, + 0); + + /* return f->x * f->y; */ + gccjit::block reading_block = fn_test_reading.new_block (); + reading_block.end_with_return (param_f.dereference_field (x) + * param_f.dereference_field (y)); + + /* Build the writer fn. */ + gccjit::type ptr_type = struct_type.get_pointer (); + gccjit::param param_g = ctxt.new_param (ptr_type, "g"); + params = {param_g}; + gccjit::function fn_test_writing + = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED, + char_type, + writer_fn_name, + params, + 0); + + /* g->x = 5; */ + gccjit::block writing_block = fn_test_writing.new_block (); + writing_block.add_assignment (param_g.dereference_field (x), + ctxt.new_rvalue (char_type, 5)); + + /* g->y = 7; */ + writing_block.add_assignment (param_g.dereference_field (y), + ctxt.new_rvalue (char_type, 7)); + + /* return READER_FN_NAME (g); */ + writing_block.end_with_return (ctxt.new_call (fn_test_reading, + param_g)); +} + +/* Implement a verifier function for a given struct. */ + +template +static void +verify_aligned_code (gcc_jit_context *ctxt, + gcc_jit_result *result, + const char *writer_fn_name) +{ + typedef int (*fn_type) (T *); + CHECK_NON_NULL (result); + + T tmp; + memset (&tmp, 0xac, sizeof (tmp)); + fn_type test_writing = + (fn_type)gcc_jit_result_get_code (result, writer_fn_name); + CHECK_NON_NULL (test_writing); + + /* Verify that the code correctly returns the product of the fields. */ + CHECK_VALUE (test_writing (&tmp), 35); + + /* Verify the we can read the values of the fields, and thus that the + struct layout agrees with that of the C++ frontend. */ + CHECK_VALUE (tmp.x, 5); + CHECK_VALUE (tmp.y, 7); +} + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + create_aligned_code (ctxt, "s2", 2, "test_aligned_reading_s2", + "test_aligned_writing_s2"); + create_aligned_code (ctxt, "s4", 4, "test_aligned_reading_s4", + "test_aligned_writing_s4"); + create_aligned_code (ctxt, "s8", 8, "test_aligned_reading_s8", + "test_aligned_writing_s8"); + create_aligned_code (ctxt, "s16", 16, "test_aligned_reading_s16", + "test_aligned_writing_s16"); + create_aligned_code (ctxt, "s32", 32, "test_aligned_reading_s32", + "test_aligned_writing_s32"); + create_aligned_code (ctxt, "s64", 64, "test_aligned_reading_s64", + "test_aligned_writing_s64"); + create_aligned_code (ctxt, "s128", 128, "test_aligned_reading_s128", + "test_aligned_writing_s128"); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + verify_aligned_code (ctxt, result, "test_aligned_writing_s2"); + verify_aligned_code (ctxt, result, "test_aligned_writing_s4"); + verify_aligned_code (ctxt, result, "test_aligned_writing_s8"); + verify_aligned_code (ctxt, result, "test_aligned_writing_s16"); + verify_aligned_code (ctxt, result, "test_aligned_writing_s32"); + verify_aligned_code (ctxt, result, "test_aligned_writing_s64"); + verify_aligned_code (ctxt, result, "test_aligned_writing_s128"); +} diff --git a/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.c b/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.c new file mode 100644 index 0000000..8f3233b --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-gcc_jit_type_get_aligned-non-power-of-two.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 *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + /* Trigger an API error by passing a bad alignment. */ + (void)gcc_jit_type_get_aligned (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_aligned:" + " alignment not a power of two: 7")); +} + -- 1.8.5.3