From: Andrea Corallo Date: Sat, 30 May 2020 09:33:08 +0000 (+0100) Subject: libgccjit: Add new gcc_jit_global_set_initializer entry point X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4ecc0061c4;p=gcc.git libgccjit: Add new gcc_jit_global_set_initializer entry point gcc/jit/ChangeLog 2020-08-01 Andrea Corallo * docs/topics/compatibility.rst (LIBGCCJIT_ABI_14): New ABI tag. * docs/topics/expressions.rst (gcc_jit_global_set_initializer): Document new entry point in section 'Global variables'. * jit-playback.c (global_new_decl, global_finalize_lvalue): New method. (playback::context::new_global): Make use of global_new_decl, global_finalize_lvalue. (load_blob_in_ctor): New template function in use by the following. (playback::context::new_global_initialized): New method. * jit-playback.h (class context): Decl 'new_global_initialized', 'global_new_decl', 'global_finalize_lvalue'. (lvalue::set_initializer): Add implementation. * jit-recording.c (recording::memento_of_get_pointer::get_size) (recording::memento_of_get_type::get_size): Add implementation. (recording::global::write_initializer_reproducer): New function in use by 'recording::global::write_reproducer'. (recording::global::replay_into) (recording::global::write_to_dump) (recording::global::write_reproducer): Handle initialized case. * jit-recording.h (class type): Decl 'get_size' and 'num_elements'. * libgccjit++.h (class lvalue): Declare new 'set_initializer' method. (class lvalue): Decl 'is_global' and 'set_initializer'. (class global) Decl 'write_initializer_reproducer'. Add 'm_initializer', 'm_initializer_num_bytes' fields. Implement 'set_initializer'. Add a destructor to free 'm_initializer'. * libgccjit.c (gcc_jit_global_set_initializer): New function. * libgccjit.h (gcc_jit_global_set_initializer): New function declaration. * libgccjit.map (LIBGCCJIT_ABI_14): New ABI tag. gcc/testsuite/ChangeLog 2020-08-01 Andrea Corallo * jit.dg/all-non-failing-tests.h: Add test-blob.c. * jit.dg/test-global-set-initializer.c: New testcase. --- diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index bb3387fa583..6bfa101ed71 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -219,3 +219,10 @@ entrypoints: * :func:`gcc_jit_version_minor` * :func:`gcc_jit_version_patchlevel` + +.. _LIBGCCJIT_ABI_14: + +``LIBGCCJIT_ABI_14`` +-------------------- +``LIBGCCJIT_ABI_14`` covers the addition of +:func:`gcc_jit_global_set_initializer` diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index d783ceea51a..b76446410de 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -582,6 +582,27 @@ Global variables referring to it. Analogous to using an "extern" global from a header file. +.. function:: gcc_jit_lvalue *\ + gcc_jit_global_set_initializer (gcc_jit_lvalue *global,\ + const void *blob,\ + size_t num_bytes) + + Set an initializer for ``global`` using the memory content pointed + by ``blob`` for ``num_bytes``. ``global`` must be an array of an + integral type. Return the global itself. + + The parameter ``blob`` must be non-NULL. The call copies the memory + pointed by ``blob`` for ``num_bytes`` bytes, so it is valid to pass + in a pointer to an on-stack buffer. The content will be stored in + the compilation unit and used as initialization value of the array. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_14`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer + Working with pointers, structs and unions ----------------------------------------- diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 0fddf04da87..4fac64dcab7 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -510,14 +510,14 @@ new_function (location *loc, return func; } -/* Construct a playback::lvalue instance (wrapping a tree). */ +/* In use by new_global and new_global_initialized. */ -playback::lvalue * +tree playback::context:: -new_global (location *loc, - enum gcc_jit_global_kind kind, - type *type, - const char *name) +global_new_decl (location *loc, + enum gcc_jit_global_kind kind, + type *type, + const char *name) { gcc_assert (type); gcc_assert (name); @@ -547,6 +547,15 @@ new_global (location *loc, if (loc) set_tree_location (inner, loc); + return inner; +} + +/* In use by new_global and new_global_initialized. */ + +playback::lvalue * +playback::context:: +global_finalize_lvalue (tree inner) +{ varpool_node::get_create (inner); varpool_node::finalize_decl (inner); @@ -556,6 +565,92 @@ new_global (location *loc, return new lvalue (this, inner); } +/* Construct a playback::lvalue instance (wrapping a tree). */ + +playback::lvalue * +playback::context:: +new_global (location *loc, + enum gcc_jit_global_kind kind, + type *type, + const char *name) +{ + tree inner = global_new_decl (loc, kind, type, name); + + return global_finalize_lvalue (inner); +} + +/* Fill 'constructor_elements' with the memory content of + 'initializer'. Each element of the initializer is of the size of + type T. In use by new_global_initialized.*/ + +template +static void +load_blob_in_ctor (vec *&constructor_elements, + size_t num_elem, + const void *initializer) +{ + /* Loosely based on 'output_init_element' c-typeck.c:9691. */ + const T *p = (const T *)initializer; + tree node = make_unsigned_type (BITS_PER_UNIT * sizeof (T)); + for (size_t i = 0; i < num_elem; i++) + { + constructor_elt celt = + { build_int_cst (long_unsigned_type_node, i), + build_int_cst (node, p[i]) }; + vec_safe_push (constructor_elements, celt); + } +} + +/* Construct an initialized playback::lvalue instance (wrapping a + tree). */ + +playback::lvalue * +playback::context:: +new_global_initialized (location *loc, + enum gcc_jit_global_kind kind, + type *type, + size_t element_size, + size_t initializer_num_elem, + const void *initializer, + const char *name) +{ + tree inner = global_new_decl (loc, kind, type, name); + + vec *constructor_elements = NULL; + + switch (element_size) + { + case 1: + load_blob_in_ctor (constructor_elements, initializer_num_elem, + initializer); + break; + case 2: + load_blob_in_ctor (constructor_elements, initializer_num_elem, + initializer); + break; + case 4: + load_blob_in_ctor (constructor_elements, initializer_num_elem, + initializer); + break; + case 8: + load_blob_in_ctor (constructor_elements, initializer_num_elem, + initializer); + break; + default: + /* This function is serving on sizes returned by 'get_size', + these are all covered by the previous cases. */ + gcc_unreachable (); + } + /* Compare with 'pop_init_level' c-typeck.c:8780. */ + tree ctor = build_constructor (type->as_tree (), constructor_elements); + constructor_elements = NULL; + + /* Compare with 'store_init_value' c-typeck.c:7555. */ + DECL_INITIAL (inner) = ctor; + + return global_finalize_lvalue (inner); +} + /* Implementation of the various gcc::jit::playback::context::new_rvalue_from_const methods. diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index f9b3e675368..50b69753bb4 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -111,6 +111,15 @@ public: type *type, const char *name); + lvalue * + new_global_initialized (location *loc, + enum gcc_jit_global_kind kind, + type *type, + size_t element_size, + size_t initializer_num_elem, + const void *initializer, + const char *name); + template rvalue * new_rvalue_from_const (type *type, @@ -266,6 +275,14 @@ private: const char * get_path_s_file () const; const char * get_path_so_file () const; + tree + global_new_decl (location *loc, + enum gcc_jit_global_kind kind, + type *type, + const char *name); + lvalue * + global_finalize_lvalue (tree inner); + private: /* Functions for implementing "compile". */ diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index a9e6528db69..3cbeba0f371 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -2175,6 +2175,61 @@ recording::type::access_as_type (reproducer &r) return r.get_identifier (this); } +/* Override of default implementation of + recording::type::get_size. + + Return the size in bytes. This is in use for global + initialization. */ + +size_t +recording::memento_of_get_type::get_size () +{ + int size; + switch (m_kind) + { + case GCC_JIT_TYPE_VOID: + return 0; + case GCC_JIT_TYPE_BOOL: + case GCC_JIT_TYPE_CHAR: + case GCC_JIT_TYPE_SIGNED_CHAR: + case GCC_JIT_TYPE_UNSIGNED_CHAR: + return 1; + case GCC_JIT_TYPE_SHORT: + case GCC_JIT_TYPE_UNSIGNED_SHORT: + size = SHORT_TYPE_SIZE; + break; + case GCC_JIT_TYPE_INT: + case GCC_JIT_TYPE_UNSIGNED_INT: + size = INT_TYPE_SIZE; + break; + case GCC_JIT_TYPE_LONG: + case GCC_JIT_TYPE_UNSIGNED_LONG: + size = LONG_TYPE_SIZE; + break; + case GCC_JIT_TYPE_LONG_LONG: + case GCC_JIT_TYPE_UNSIGNED_LONG_LONG: + size = LONG_LONG_TYPE_SIZE; + break; + case GCC_JIT_TYPE_FLOAT: + size = FLOAT_TYPE_SIZE; + break; + case GCC_JIT_TYPE_DOUBLE: + size = DOUBLE_TYPE_SIZE; + break; + case GCC_JIT_TYPE_LONG_DOUBLE: + size = LONG_DOUBLE_TYPE_SIZE; + break; + default: + /* As this function is called by + 'gcc_jit_global_set_initializer' and + 'recording::global::write_reproducer' possible types are only + integrals and are covered by the previous cases. */ + gcc_unreachable (); + } + + return size / BITS_PER_UNIT; +} + /* Implementation of pure virtual hook recording::type::dereference for recording::memento_of_get_type. */ @@ -2482,6 +2537,15 @@ recording::memento_of_get_type::write_reproducer (reproducer &r) /* The implementation of class gcc::jit::recording::memento_of_get_pointer. */ +/* Override of default implementation of + recording::type::get_size for get_pointer. */ + +size_t +recording::memento_of_get_pointer::get_size () +{ + return POINTER_SIZE / BITS_PER_UNIT; +} + /* Override of default implementation of recording::type::accepts_writes_from for get_pointer. @@ -4393,10 +4457,20 @@ recording::block::dump_edges_to_dot (pretty_printer *pp) void recording::global::replay_into (replayer *r) { - set_playback_obj (r->new_global (playback_location (r, m_loc), - m_kind, - m_type->playback_type (), - playback_string (m_name))); + set_playback_obj ( + m_initializer + ? r->new_global_initialized (playback_location (r, m_loc), + m_kind, + m_type->playback_type (), + m_type->dereference ()->get_size (), + m_initializer_num_bytes + / m_type->dereference ()->get_size (), + m_initializer, + playback_string (m_name)) + : r->new_global (playback_location (r, m_loc), + m_kind, + m_type->playback_type (), + playback_string (m_name))); } /* Override the default implementation of @@ -4440,9 +4514,26 @@ recording::global::write_to_dump (dump &d) d.write ("extern "); break; } - d.write ("%s %s;\n", + + d.write ("%s %s", m_type->get_debug_string (), get_debug_string ()); + + if (!m_initializer) + { + d.write (";\n"); + return; + } + + d.write ("=\n { "); + const unsigned char *p = (const unsigned char *)m_initializer; + for (size_t i = 0; i < m_initializer_num_bytes; i++) + { + d.write ("0x%x, ", p[i]); + if (i && !(i % 64)) + d.write ("\n "); + } + d.write ("};\n"); } /* A table of enum gcc_jit_global_kind values expressed in string @@ -4454,6 +4545,27 @@ static const char * const global_kind_reproducer_strings[] = { "GCC_JIT_GLOBAL_IMPORTED" }; +template +void +recording::global::write_initializer_reproducer (const char *id, reproducer &r) +{ + const char *init_id = r.make_tmp_identifier ("init_for", this); + r.write (" %s %s[] =\n {", + m_type->dereference ()->get_debug_string (), + init_id); + + const T *p = (const T *)m_initializer; + for (size_t i = 0; i < m_initializer_num_bytes / sizeof (T); i++) + { + r.write ("%" PRIu64 ", ", (uint64_t)p[i]); + if (i && !(i % 64)) + r.write ("\n "); + } + r.write ("};\n"); + r.write (" gcc_jit_global_set_initializer (%s, %s, sizeof (%s));\n", + id, init_id, init_id); +} + /* Implementation of recording::memento::write_reproducer for globals. */ void @@ -4472,6 +4584,27 @@ recording::global::write_reproducer (reproducer &r) global_kind_reproducer_strings[m_kind], r.get_identifier_as_type (get_type ()), m_name->get_debug_string ()); + + if (m_initializer) + switch (m_type->dereference ()->get_size ()) + { + case 1: + write_initializer_reproducer (id, r); + break; + case 2: + write_initializer_reproducer (id, r); + break; + case 4: + write_initializer_reproducer (id, r); + break; + case 8: + write_initializer_reproducer (id, r); + break; + default: + /* This function is serving on sizes returned by 'get_size', + these are all covered by the previous cases. */ + gcc_unreachable (); + } } /* The implementation of the various const-handling classes: diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 726b9c4b837..30e37aff387 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -502,6 +502,12 @@ public: This will return NULL if it's not valid to dereference this type. The caller is responsible for setting an error. */ virtual type *dereference () = 0; + /* Get the type size in bytes. + + This is implemented only for memento_of_get_type and + memento_of_get_pointer as it is used for initializing globals of + these types. */ + virtual size_t get_size () { gcc_unreachable (); } /* Dynamic casts. */ virtual function_type *dyn_cast_function_type () { return NULL; } @@ -569,6 +575,8 @@ public: type *dereference () FINAL OVERRIDE; + size_t get_size () FINAL OVERRIDE; + bool accepts_writes_from (type *rtype) FINAL OVERRIDE { if (m_kind == GCC_JIT_TYPE_VOID_PTR) @@ -610,6 +618,8 @@ public: type *dereference () FINAL OVERRIDE { return m_other_type; } + size_t get_size () FINAL OVERRIDE; + bool accepts_writes_from (type *rtype) FINAL OVERRIDE; void replay_into (replayer *r) FINAL OVERRIDE; @@ -755,6 +765,7 @@ class array_type : public type bool is_bool () const FINAL OVERRIDE { return false; } type *is_pointer () FINAL OVERRIDE { return NULL; } type *is_array () FINAL OVERRIDE { return m_element_type; } + int num_elements () { return m_num_elements; } void replay_into (replayer *) FINAL OVERRIDE; @@ -1107,6 +1118,7 @@ public: const char *access_as_rvalue (reproducer &r) OVERRIDE; virtual const char *access_as_lvalue (reproducer &r); + virtual bool is_global () const { return false; } }; class param : public lvalue @@ -1327,7 +1339,14 @@ public: : lvalue (ctxt, loc, type), m_kind (kind), m_name (name) - {} + { + m_initializer = NULL; + m_initializer_num_bytes = 0; + } + ~global () + { + free (m_initializer); + } void replay_into (replayer *) FINAL OVERRIDE; @@ -1335,8 +1354,23 @@ public: void write_to_dump (dump &d) FINAL OVERRIDE; + bool is_global () const FINAL OVERRIDE { return true; } + + void + set_initializer (const void *initializer, + size_t num_bytes) + { + if (m_initializer) + free (m_initializer); + m_initializer = xmalloc (num_bytes); + memcpy (m_initializer, initializer, num_bytes); + m_initializer_num_bytes = num_bytes; + } + private: string * make_debug_string () FINAL OVERRIDE { return m_name; } + template + void write_initializer_reproducer (const char *id, reproducer &r); void write_reproducer (reproducer &r) FINAL OVERRIDE; enum precedence get_precedence () const FINAL OVERRIDE { @@ -1346,6 +1380,8 @@ private: private: enum gcc_jit_global_kind m_kind; string *m_name; + void *m_initializer; + size_t m_initializer_num_bytes; }; template diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 69e67766640..1b9ef1a5db9 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -488,6 +488,7 @@ namespace gccjit location loc = location ()); rvalue get_address (location loc = location ()); + lvalue set_initializer (const void *blob, size_t num_bytes); }; class param : public lvalue @@ -1737,6 +1738,15 @@ lvalue::get_address (location loc) loc.get_inner_location ())); } +inline lvalue +lvalue::set_initializer (const void *blob, size_t num_bytes) +{ + gcc_jit_global_set_initializer (get_inner_lvalue (), + blob, + num_bytes); + return *this; +} + // class param : public lvalue inline param::param () : lvalue () {} inline param::param (gcc_jit_param *inner) diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 50130fbbe00..a00aefc7108 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -1117,6 +1117,45 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt, return (gcc_jit_lvalue *)ctxt->new_global (loc, kind, type, name); } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::global::set_initializer method, in + jit-recording.c. */ + +extern gcc_jit_lvalue * +gcc_jit_global_set_initializer (gcc_jit_lvalue *global, + const void *blob, + size_t num_bytes) +{ + RETURN_NULL_IF_FAIL (global, NULL, NULL, "NULL global"); + RETURN_NULL_IF_FAIL (blob, NULL, NULL, "NULL blob"); + RETURN_NULL_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL, + "lvalue \"%s\" not a global", + global->get_debug_string ()); + + gcc::jit::recording::type *lval_type = global->get_type (); + RETURN_NULL_IF_FAIL_PRINTF1 (lval_type->is_array (), NULL, NULL, + "global \"%s\" is not an array", + global->get_debug_string ()); + RETURN_NULL_IF_FAIL_PRINTF1 (lval_type->dereference ()->is_int (), NULL, NULL, + "global \"%s\" is not an array of integral type", + global->get_debug_string ()); + size_t lvalue_size = + lval_type->dereference ()->get_size () + * static_cast (lval_type)->num_elements (); + RETURN_NULL_IF_FAIL_PRINTF3 ( + lvalue_size == num_bytes, NULL, NULL, + "mismatching sizes:" + " global \"%s\" has size %zu whereas initializer has size %zu", + global->get_debug_string (), lvalue_size, num_bytes); + + reinterpret_cast (global) + ->set_initializer (blob, num_bytes); + + return global; +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, this calls the trivial diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 1c5a12e9c01..7134841bb07 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -788,6 +788,21 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt, gcc_jit_type *type, const char *name); +#define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer + +/* Set an initial value for a global, which must be an array of + integral type. Return the global itself. + + This API entrypoint was added in LIBGCCJIT_ABI_14; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_initializer +*/ + +extern gcc_jit_lvalue * +gcc_jit_global_set_initializer (gcc_jit_lvalue *global, + const void *blob, + size_t num_bytes); + /* Upcasting. */ extern gcc_jit_object * gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue); diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 6137dd4b4b0..a6e67e781a4 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -186,4 +186,9 @@ LIBGCCJIT_ABI_13 { gcc_jit_version_major; gcc_jit_version_minor; gcc_jit_version_patchlevel; -} LIBGCCJIT_ABI_12; \ No newline at end of file +} LIBGCCJIT_ABI_12; + +LIBGCCJIT_ABI_14 { + global: + gcc_jit_global_set_initializer; +} LIBGCCJIT_ABI_13; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 632ab8cfb2e..4202eb7798b 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -174,6 +174,13 @@ #undef create_code #undef verify_code +/* test-global-set-initializer.c */ +#define create_code create_code_global_set_initializer +#define verify_code verify_code_global_set_initializer +#include "test-global-set-initializer.c" +#undef create_code +#undef verify_code + /* test-hello-world.c */ #define create_code create_code_hello_world #define verify_code verify_code_hello_world diff --git a/gcc/testsuite/jit.dg/test-global-set-initializer.c b/gcc/testsuite/jit.dg/test-global-set-initializer.c new file mode 100644 index 00000000000..d38aba7d73f --- /dev/null +++ b/gcc/testsuite/jit.dg/test-global-set-initializer.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +#define BIG_BLOB_SIZE (1 << 12) /* 4KB. */ + +static signed char test_blob1[] = { 0xc, 0xa, 0xf, 0xf, 0xe }; +static unsigned test_blob2[] = { 0x3, 0x2, 0x1, 0x0, 0x1, 0x2, 0x3 }; +static unsigned char test_blob3[BIG_BLOB_SIZE]; + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + signed char bin_blob1[] = { 0xc, 0xa, 0xf, 0xf, 0xe }; + unsigned bin_blob2[] = { 0x3, 0x2, 0x1, 0x0, 0x1, 0x2, 0x3 }; + unsigned char bin_blob3[4096]... + */ + gcc_jit_type *unsigned_char_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR); + gcc_jit_type *signed_char_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIGNED_CHAR); + gcc_jit_type *unsigned_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_INT); + + gcc_jit_lvalue *glob = + gcc_jit_context_new_global ( + ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, + gcc_jit_context_new_array_type (ctxt, NULL, signed_char_type, + sizeof (test_blob1)), + "bin_blob1"); + gcc_jit_global_set_initializer (glob, test_blob1, sizeof (test_blob1)); + + glob = + gcc_jit_context_new_global ( + ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, + gcc_jit_context_new_array_type ( + ctxt, NULL, unsigned_type, + sizeof (test_blob2) / sizeof (*test_blob2)), + "bin_blob2"); + gcc_jit_global_set_initializer (glob, test_blob2, + sizeof (test_blob2)); + + for (size_t i = 0; i < BIG_BLOB_SIZE; i++) + test_blob3[i] = i * i + i; + glob = + gcc_jit_context_new_global ( + ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, + gcc_jit_context_new_array_type (ctxt, NULL, unsigned_char_type, + sizeof (test_blob3)), + "bin_blob3"); + gcc_jit_global_set_initializer (glob, test_blob3, sizeof (test_blob3)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_NON_NULL (result); + void *glob = gcc_jit_result_get_global (result, "bin_blob1"); + CHECK_NON_NULL (glob); + CHECK_VALUE (memcmp (test_blob1, glob, sizeof (test_blob1)), 0); + + glob = gcc_jit_result_get_global (result, "bin_blob2"); + CHECK_NON_NULL (glob); + CHECK_VALUE (memcmp (test_blob2, glob, + sizeof (test_blob2)), 0); + + glob = gcc_jit_result_get_global (result, "bin_blob3"); + CHECK_NON_NULL (glob); + CHECK_VALUE (memcmp (test_blob3, glob, sizeof (test_blob3)), 0); + +}