diff options
author | Andrea Corallo <andrea.corallo@arm.com> | 2020-05-30 10:33:08 +0100 |
---|---|---|
committer | Andrea Corallo <andrea.corallo@arm.com> | 2020-09-11 12:18:59 +0200 |
commit | 4ecc0061c400102859dd630cce84d1cc5be0fbf7 (patch) | |
tree | 7d5e9b91b960800e48074ba848e723990048acaf /gcc/jit | |
parent | 15545563128f0240192c263522d4a36b7f86250f (diff) | |
download | gcc-4ecc0061c400102859dd630cce84d1cc5be0fbf7.zip gcc-4ecc0061c400102859dd630cce84d1cc5be0fbf7.tar.gz gcc-4ecc0061c400102859dd630cce84d1cc5be0fbf7.tar.bz2 |
libgccjit: Add new gcc_jit_global_set_initializer entry point
gcc/jit/ChangeLog
2020-08-01 Andrea Corallo <andrea.corallo@arm.com>
* 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 <andrea.corallo@arm.com>
* jit.dg/all-non-failing-tests.h: Add test-blob.c.
* jit.dg/test-global-set-initializer.c: New testcase.
Diffstat (limited to 'gcc/jit')
-rw-r--r-- | gcc/jit/docs/topics/compatibility.rst | 7 | ||||
-rw-r--r-- | gcc/jit/docs/topics/expressions.rst | 21 | ||||
-rw-r--r-- | gcc/jit/jit-playback.c | 107 | ||||
-rw-r--r-- | gcc/jit/jit-playback.h | 17 | ||||
-rw-r--r-- | gcc/jit/jit-recording.c | 143 | ||||
-rw-r--r-- | gcc/jit/jit-recording.h | 38 | ||||
-rw-r--r-- | gcc/jit/libgccjit++.h | 10 | ||||
-rw-r--r-- | gcc/jit/libgccjit.c | 39 | ||||
-rw-r--r-- | gcc/jit/libgccjit.h | 15 | ||||
-rw-r--r-- | gcc/jit/libgccjit.map | 7 |
10 files changed, 391 insertions, 13 deletions
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index bb3387f..6bfa101 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 d783cee..b764464 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 0fddf04..4fac64d 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<typename T> +static void +load_blob_in_ctor (vec<constructor_elt, va_gc> *&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_elt, va_gc> *constructor_elements = NULL; + + switch (element_size) + { + case 1: + load_blob_in_ctor<uint8_t> (constructor_elements, initializer_num_elem, + initializer); + break; + case 2: + load_blob_in_ctor<uint16_t> (constructor_elements, initializer_num_elem, + initializer); + break; + case 4: + load_blob_in_ctor<uint32_t> (constructor_elements, initializer_num_elem, + initializer); + break; + case 8: + load_blob_in_ctor<uint64_t> (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 <HOST_TYPE> methods. diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index f9b3e67..50b6975 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 <typename HOST_TYPE> 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 a9e6528..3cbeba0 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. */ @@ -2483,6 +2538,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. Require a pointer type, and allowing writes to @@ -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 <typename T> +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<uint8_t> (id, r); + break; + case 2: + write_initializer_reproducer<uint16_t> (id, r); + break; + case 4: + write_initializer_reproducer<uint32_t> (id, r); + break; + case 8: + write_initializer_reproducer<uint64_t> (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 726b9c4..30e37af 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 <typename T> + 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 <typename HOST_TYPE> diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 69e6776..1b9ef1a 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 50130fb..a00aefc 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -1119,6 +1119,45 @@ gcc_jit_context_new_global (gcc_jit_context *ctxt, /* 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 <gcc::jit::recording::array_type *> (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 <gcc::jit::recording::global *> (global) + ->set_initializer (blob, num_bytes); + + return global; +} + +/* Public entrypoint. See description in libgccjit.h. + After error-checking, this calls the trivial gcc::jit::recording::memento::as_object method (an lvalue is a memento), in jit-recording.h. */ diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 1c5a12e..7134841 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 6137dd4..a6e67e78 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; |