diff options
author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2024-01-10 15:23:37 +0100 |
---|---|---|
committer | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2024-01-12 11:12:18 +0100 |
commit | 109985343bcada8936cb83d1fd3cb9cad915fb4a (patch) | |
tree | c36ab5ac651e9bad51e1d466e5acf43018d6d41f /gcc/jit | |
parent | d8c1361220ba7617adf4ccc396499f6393ec223e (diff) | |
download | gcc-109985343bcada8936cb83d1fd3cb9cad915fb4a.zip gcc-109985343bcada8936cb83d1fd3cb9cad915fb4a.tar.gz gcc-109985343bcada8936cb83d1fd3cb9cad915fb4a.tar.bz2 |
[PATCH] libgccjit: Add support for function attributes and variable attributes.
gcc/jit/ChangeLog:
* dummy-frontend.cc (handle_alias_attribute): New function.
(handle_always_inline_attribute): New function.
(handle_cold_attribute): New function.
(handle_fnspec_attribute): New function.
(handle_format_arg_attribute): New function.
(handle_format_attribute): New function.
(handle_noinline_attribute): New function.
(handle_target_attribute): New function.
(handle_used_attribute): New function.
(handle_visibility_attribute): New function.
(handle_weak_attribute): New function.
(handle_alias_ifunc_attribute): New function.
* jit-playback.cc (fn_attribute_to_string): New function.
(variable_attribute_to_string): New function.
(global_new_decl): Add attributes support.
(set_variable_attribute): New function.
(new_global): Add attributes support.
(new_global_initialized): Add attributes support.
(new_local): Add attributes support.
* jit-playback.h (fn_attribute_to_string): New function.
(set_variable_attribute): New function.
* jit-recording.cc (recording::lvalue::add_attribute): New function.
(recording::function::function): New function.
(recording::function::write_to_dump): Add attributes support.
(recording::function::add_attribute): New function.
(recording::function::add_string_attribute): New function.
(recording::function::add_integer_array_attribute): New function.
(recording::global::replay_into): Add attributes support.
(recording::local::replay_into): Add attributes support.
* jit-recording.h: Add attributes support.
* libgccjit.cc (gcc_jit_function_add_attribute): New function.
(gcc_jit_function_add_string_attribute): New function.
(gcc_jit_function_add_integer_array_attribute): New function.
(gcc_jit_lvalue_add_attribute): New function.
* libgccjit.h (enum gcc_jit_fn_attribute): New enum.
(gcc_jit_function_add_attribute): New function.
(gcc_jit_function_add_string_attribute): New function.
(gcc_jit_function_add_integer_array_attribute): New function.
(enum gcc_jit_variable_attribute): New function.
(gcc_jit_lvalue_add_string_attribute): New function.
* libgccjit.map: Declare new functions.
gcc/testsuite/ChangeLog:
* jit.dg/all-non-failing-tests.h: Add new attributes tests.
* jit.dg/jit.exp: Add `jit-verify-assembler-output-not` test command.
* jit.dg/test-restrict-attribute.c: New test.
* jit.dg/test-alias-attribute.c: New test.
* jit.dg/test-always_inline-attribute.c: New test.
* jit.dg/test-cold-attribute.c: New test.
* jit.dg/test-const-attribute.c: New test.
* jit.dg/test-noinline-attribute.c: New test.
* jit.dg/test-nonnull-attribute.c: New test.
* jit.dg/test-pure-attribute.c: New test.
* jit.dg/test-used-attribute.c: New test.
* jit.dg/test-variable-attribute.c: New test.
* jit.dg/test-weak-attribute.c: New test.
gcc/jit/ChangeLog:
* docs/topics/compatibility.rst: Add documentation for LIBGCCJIT_ABI_26.
* docs/topics/functions.rst: Add documentation for new functions.
* docs/topics/expressions.rst: Add documentation for new functions.
Co-authored-by: Antoni Boucher <bouanto@zoho.com>
Signed-off-by: Guillaume Gomez <guillaume1.gomez@gmail.com>
Diffstat (limited to 'gcc/jit')
-rw-r--r-- | gcc/jit/docs/topics/compatibility.rst | 12 | ||||
-rw-r--r-- | gcc/jit/docs/topics/expressions.rst | 17 | ||||
-rw-r--r-- | gcc/jit/docs/topics/functions.rst | 63 | ||||
-rw-r--r-- | gcc/jit/dummy-frontend.cc | 512 | ||||
-rw-r--r-- | gcc/jit/jit-playback.cc | 169 | ||||
-rw-r--r-- | gcc/jit/jit-playback.h | 37 | ||||
-rw-r--r-- | gcc/jit/jit-recording.cc | 166 | ||||
-rw-r--r-- | gcc/jit/jit-recording.h | 22 | ||||
-rw-r--r-- | gcc/jit/libgccjit.cc | 67 | ||||
-rw-r--r-- | gcc/jit/libgccjit.h | 55 | ||||
-rw-r--r-- | gcc/jit/libgccjit.map | 8 |
11 files changed, 1055 insertions, 73 deletions
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 704de1b..cbf5b41 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -378,3 +378,15 @@ alignment of a variable: -------------------- ``LIBGCCJIT_ABI_25`` covers the addition of :func:`gcc_jit_type_get_restrict` + +.. _LIBGCCJIT_ABI_26: + +``LIBGCCJIT_ABI_26`` +-------------------- +``LIBGCCJIT_ABI_26`` covers the addition of functions to set attributes +on functions and variables: + + * :func:`gcc_jit_function_add_attribute` + * :func:`gcc_jit_function_add_string_attribute` + * :func:`gcc_jit_function_add_integer_array_attribute` + * :func:`gcc_jit_lvalue_add_string_attribute` diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index cee6a30..35ee05c 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -944,6 +944,23 @@ Global variables #ifdef LIBGCCJIT_HAVE_CTORS +Variables +********* + +.. function:: void\ + gcc_jit_lvalue_add_string_attribute (gcc_jit_lvalue *variable, + enum gcc_jit_variable_attribute attribute, + const char *value) + + Add an attribute ``attribute`` with value ``value`` to a variable ``variable``. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_ATTRIBUTES + Working with pointers, structs and unions ----------------------------------------- diff --git a/gcc/jit/docs/topics/functions.rst b/gcc/jit/docs/topics/functions.rst index 127bc0e..804605e 100644 --- a/gcc/jit/docs/topics/functions.rst +++ b/gcc/jit/docs/topics/functions.rst @@ -197,6 +197,69 @@ Functions .. type:: gcc_jit_case +.. function:: void\ + gcc_jit_function_add_attribute (gcc_jit_function *func, + enum gcc_jit_fn_attribute attribute) + + Add an attribute ``attribute`` to a function ``func``. + + This is equivalent to the following code: + + .. code-block:: c + + __attribute__((always_inline)) + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_ATTRIBUTES + +.. function:: void\ + gcc_jit_function_add_string_attribute (gcc_jit_function *func, + enum gcc_jit_fn_attribute attribute, + const char *value) + + Add a string attribute ``attribute`` with value ``value`` to a function + ``func``. + + This is equivalent to the following code: + + .. code-block:: c + + __attribute__ ((alias ("xxx"))) + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_ATTRIBUTES + +.. function:: void\ + gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func, + enum gcc_jit_fn_attribute attribute, + const int *value, + size_t length) + + Add an attribute ``attribute`` with ``length`` integer values ``value`` to a + function ``func``. The integer values must be the same as you would write + them in a C code. + + This is equivalent to the following code: + + .. code-block:: c + + __attribute__ ((nonnull (1, 2))) + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_26`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_ATTRIBUTES + Blocks ------ .. type:: gcc_jit_block diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index 211f1be..dbeeacd 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -29,30 +29,42 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "stringpool.h" #include "attribs.h" +#include "cgraph.h" +#include "target.h" #include <mpfr.h> /* Attribute handling. */ -static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); -static tree handle_leaf_attribute (tree *, tree, tree, int, bool *); +static tree handle_alias_attribute (tree *, tree, tree, int, bool *); +static tree handle_always_inline_attribute (tree *, tree, tree, int, + bool *); +static tree handle_cold_attribute (tree *, tree, tree, int, bool *); static tree handle_const_attribute (tree *, tree, tree, int, bool *); +static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); +static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); +static tree handle_format_attribute (tree *, tree, tree, int, bool *); +static tree handle_leaf_attribute (tree *, tree, tree, int, bool *); static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); -static tree handle_pure_attribute (tree *, tree, tree, int, bool *); -static tree handle_novops_attribute (tree *, tree, tree, int, bool *); +static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); +static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); -static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); -static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); -static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); -static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); +static tree handle_novops_attribute (tree *, tree, tree, int, bool *); static tree handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *); -static tree ignore_attribute (tree *, tree, tree, int, bool *); +static tree handle_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); +static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); +static tree handle_target_attribute (tree *, tree, tree, int, bool *); +static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); +static tree handle_used_attribute (tree *, tree, tree, int, bool *); +static tree handle_visibility_attribute (tree *, tree, tree, int, + bool *); +static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ; -static tree handle_format_attribute (tree *, tree, tree, int, bool *); -static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); -static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); +static tree ignore_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -61,7 +73,6 @@ static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); /* Define attributes that are mutually exclusive with one another. */ static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = { - ATTR_EXCL ("noreturn", true, true, true), ATTR_EXCL ("alloc_align", true, true, true), ATTR_EXCL ("alloc_size", true, true, true), ATTR_EXCL ("const", true, true, true), @@ -78,57 +89,117 @@ static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] = ATTR_EXCL (NULL, false, false, false), }; +/* Exclusions that apply to attribute alloc_align, alloc_size, and malloc. */ +static const struct attribute_spec::exclusions attr_alloc_exclusions[] = +{ + ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = { ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("alloc_align", true, true, true), + ATTR_EXCL ("alloc_size", true, true, true), + ATTR_EXCL ("malloc", true, true, true), ATTR_EXCL ("noreturn", true, true, true), ATTR_EXCL ("pure", true, true, true), ATTR_EXCL (NULL, false, false, false) }; +static const struct attribute_spec::exclusions attr_always_inline_exclusions[] = +{ + ATTR_EXCL ("noinline", true, true, true), + ATTR_EXCL ("target_clones", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] = +{ + ATTR_EXCL ("cold", true, true, true), + ATTR_EXCL ("hot", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + +static const struct attribute_spec::exclusions attr_noinline_exclusions[] = +{ + ATTR_EXCL ("always_inline", true, true, true), + ATTR_EXCL ("gnu_inline", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_target_exclusions[] = +{ + ATTR_EXCL ("target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE, + TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE), + ATTR_EXCL (NULL, false, false, false), +}; + /* Table of machine-independent attributes supported in libgccjit. */ static const attribute_spec jit_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ - { "noreturn", 0, 0, true, false, false, false, - handle_noreturn_attribute, - attr_noreturn_exclusions }, - { "leaf", 0, 0, true, false, false, false, - handle_leaf_attribute, NULL }, + { "alias", 1, 1, true, false, false, false, + handle_alias_attribute, NULL }, + { "always_inline", 0, 0, true, false, false, false, + handle_always_inline_attribute, + attr_always_inline_exclusions }, + { "cold", 0, 0, true, false, false, false, + handle_cold_attribute, + attr_cold_hot_exclusions }, /* The same comments as for noreturn attributes apply to const ones. */ - { "const", 0, 0, true, false, false, false, + { "const", 0, 0, true, false, false, false, handle_const_attribute, attr_const_pure_exclusions }, - { "malloc", 0, 0, true, false, false, false, - handle_malloc_attribute, NULL }, - { "pure", 0, 0, true, false, false, false, - handle_pure_attribute, - attr_const_pure_exclusions }, - { "no vops", 0, 0, true, false, false, false, + { "fn spec", 1, 1, false, true, true, false, + handle_fnspec_attribute, NULL }, + + { "leaf", 0, 0, true, false, false, false, + handle_leaf_attribute, NULL }, + { "malloc", 0, 0, true, false, false, false, + handle_malloc_attribute, attr_alloc_exclusions }, + { "noreturn", 0, 0, true, false, false, false, + handle_noreturn_attribute, + attr_noreturn_exclusions }, + { "no vops", 0, 0, true, false, false, false, handle_novops_attribute, NULL }, - { "nonnull", 0, -1, false, true, true, false, + { "noinline", 0, 0, true, false, false, false, + handle_noinline_attribute, + attr_noinline_exclusions }, + { "nonnull", 0, -1, false, true, true, false, handle_nonnull_attribute, NULL }, - { "nothrow", 0, 0, true, false, false, false, + { "nothrow", 0, 0, true, false, false, false, handle_nothrow_attribute, NULL }, { "patchable_function_entry", 1, 2, true, false, false, false, handle_patchable_function_entry_attribute, NULL }, - { "returns_twice", 0, 0, true, false, false, false, + { "pure", 0, 0, true, false, false, false, + handle_pure_attribute, + attr_const_pure_exclusions }, + { "returns_twice", 0, 0, true, false, false, false, handle_returns_twice_attribute, attr_returns_twice_exclusions }, - { "sentinel", 0, 1, false, true, true, false, + { "sentinel", 0, 1, false, true, true, false, handle_sentinel_attribute, NULL }, - { "type generic", 0, 0, false, true, true, false, + { "target", 1, -1, true, false, false, false, + handle_target_attribute, attr_target_exclusions }, + { "type generic", 0, 0, false, true, true, false, handle_type_generic_attribute, NULL }, - { "fn spec", 1, 1, false, true, true, false, - handle_fnspec_attribute, NULL }, { "transaction_pure", 0, 0, false, true, true, false, handle_transaction_pure_attribute, NULL }, + { "used", 0, 0, true, false, false, false, + handle_used_attribute, NULL }, + { "visibility", 1, 1, false, false, false, false, + handle_visibility_attribute, NULL }, + { "weak", 0, 0, true, false, false, false, + handle_weak_attribute, NULL }, /* For internal use only. The leading '*' both prevents its usage in source code and signals that it may be overridden by machine tables. */ { "*tm regparm", 0, 0, false, true, true, false, - ignore_attribute, NULL } + ignore_attribute, NULL }, }; static const scoped_attribute_specs jit_gnu_attribute_table = @@ -143,7 +214,7 @@ static const attribute_spec jit_format_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ - { "format", 3, 3, false, true, true, false, + { "format", 3, 3, false, true, true, false, handle_format_attribute, NULL }, { "format_arg", 1, 1, false, true, true, false, handle_format_arg_attribute, NULL } @@ -212,14 +283,9 @@ handle_leaf_attribute (tree *node, tree name, struct attribute_spec.handler. */ static tree -handle_const_attribute (tree *node, tree ARG_UNUSED (name), - tree ARG_UNUSED (args), int ARG_UNUSED (flags), - bool * ARG_UNUSED (no_add_attrs)) +handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) { - if (TREE_CODE (*node) != FUNCTION_DECL - || !fndecl_built_in_p (*node)) - inform (UNKNOWN_LOCATION, "%s:%s: %E: %E", __FILE__, __func__, *node, name); - tree type = TREE_TYPE (*node); /* See FIXME comment on noreturn in c_common_attribute_table. */ @@ -228,11 +294,16 @@ handle_const_attribute (tree *node, tree ARG_UNUSED (name), else if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) TREE_TYPE (*node) - = build_pointer_type - (build_type_variant (TREE_TYPE (type), 1, - TREE_THIS_VOLATILE (TREE_TYPE (type)))); + = (build_qualified_type + (build_pointer_type + (build_type_variant (TREE_TYPE (type), 1, + TREE_THIS_VOLATILE (TREE_TYPE (type)))), + TYPE_QUALS (type))); else - gcc_unreachable (); + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } return NULL_TREE; } @@ -494,6 +565,357 @@ handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), return NULL_TREE; } +/* Handle an "visibility" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_visibility_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), + bool *ARG_UNUSED (no_add_attrs)) +{ + tree decl = *node; + tree id = TREE_VALUE (args); + enum symbol_visibility vis; + + if (TYPE_P (*node)) + { + if (TREE_CODE (*node) == ENUMERAL_TYPE) + /* OK. */; + else if (!RECORD_OR_UNION_TYPE_P (*node)) + { + warning (OPT_Wattributes, "%qE attribute ignored on non-class types", + name); + return NULL_TREE; + } + else if (TYPE_FIELDS (*node)) + { + error ("%qE attribute ignored because %qT is already defined", + name, *node); + return NULL_TREE; + } + } + else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl)) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + return NULL_TREE; + } + + if (TREE_CODE (id) != STRING_CST) + { + error ("visibility argument not a string"); + return NULL_TREE; + } + + /* If this is a type, set the visibility on the type decl. */ + if (TYPE_P (decl)) + { + decl = TYPE_NAME (decl); + if (!decl) + return NULL_TREE; + if (TREE_CODE (decl) == IDENTIFIER_NODE) + { + warning (OPT_Wattributes, "%qE attribute ignored on types", + name); + return NULL_TREE; + } + } + + if (strcmp (TREE_STRING_POINTER (id), "default") == 0) + vis = VISIBILITY_DEFAULT; + else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0) + vis = VISIBILITY_INTERNAL; + else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0) + vis = VISIBILITY_HIDDEN; + else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0) + vis = VISIBILITY_PROTECTED; + else + { + error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs", + name, "default", "hidden", "protected", "internal"); + vis = VISIBILITY_DEFAULT; + } + + if (DECL_VISIBILITY_SPECIFIED (decl) + && vis != DECL_VISIBILITY (decl)) + { + tree attributes = (TYPE_P (*node) + ? TYPE_ATTRIBUTES (*node) + : DECL_ATTRIBUTES (decl)); + if (lookup_attribute ("visibility", attributes)) + error ("%qD redeclared with different visibility", decl); + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && lookup_attribute ("dllimport", attributes)) + error ("%qD was declared %qs which implies default visibility", + decl, "dllimport"); + else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES + && lookup_attribute ("dllexport", attributes)) + error ("%qD was declared %qs which implies default visibility", + decl, "dllexport"); + } + + DECL_VISIBILITY (decl) = vis; + DECL_VISIBILITY_SPECIFIED (decl) = 1; + + /* Go ahead and attach the attribute to the node as well. This is needed + so we can determine whether we have VISIBILITY_DEFAULT because the + visibility was not specified, or because it was explicitly overridden + from the containing scope. */ + + return NULL_TREE; +} + +/* Handle a "always_inline" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_always_inline_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + { + /* Set the attribute and mark it for disregarding inline + limits. */ + DECL_DISREGARD_INLINE_LIMITS (*node) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "cold" and attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + || TREE_CODE (*node) == LABEL_DECL) + { + /* Attribute cold processing is done later with lookup_attribute. */ + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "noinline" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_noinline_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + DECL_UNINLINABLE (*node) = 1; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle a "weak" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_weak_attribute (tree *node, tree name, + tree ARG_UNUSED (args), + int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (*node)) + { + warning (OPT_Wattributes, "inline function %q+D declared weak", *node); + *no_add_attrs = true; + } + else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node))) + { + error ("indirect function %q+D cannot be declared weak", *node); + *no_add_attrs = true; + return NULL_TREE; + } + else if (VAR_OR_FUNCTION_DECL_P (*node)) + declare_weak (*node); + else + warning (OPT_Wattributes, "%qE attribute ignored", name); + + return NULL_TREE; +} + +/* Handle a "target" attribute. */ + +static tree +handle_target_attribute (tree *node, tree name, tree args, int flags, + bool *no_add_attrs) +{ + /* Ensure we have a function declaration. */ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + else if (! targetm.target_option.valid_attribute_p (*node, name, args, + flags)) + *no_add_attrs = true; + + /* Check that there's no empty string in values of the attribute. */ + for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t)) + { + tree value = TREE_VALUE (t); + if (TREE_CODE (value) == STRING_CST + && TREE_STRING_LENGTH (value) == 1 + && TREE_STRING_POINTER (value)[0] == '\0') + { + warning (OPT_Wattributes, "empty string in attribute %<target%>"); + *no_add_attrs = true; + } + } + + return NULL_TREE; +} + +/* Handle a "used" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree node = *pnode; + + if (TREE_CODE (node) == FUNCTION_DECL + || (VAR_P (node) && TREE_STATIC (node)) + || (TREE_CODE (node) == TYPE_DECL)) + { + TREE_USED (node) = 1; + DECL_PRESERVE_P (node) = 1; + if (VAR_P (node)) + DECL_READ_P (node) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Handle an "alias" or "ifunc" attribute; arguments as in + struct attribute_spec.handler, except that IS_ALIAS tells us + whether this is an alias as opposed to ifunc attribute. */ + +static tree +handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args, + bool *no_add_attrs) +{ + tree decl = *node; + + if (TREE_CODE (decl) != FUNCTION_DECL + && (!is_alias || !VAR_P (decl))) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) + || (TREE_CODE (decl) != FUNCTION_DECL + && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) + /* A static variable declaration is always a tentative definition, + but the alias is a non-tentative definition which overrides. */ + || (TREE_CODE (decl) != FUNCTION_DECL + && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl))) + { + error ("%q+D defined both normally and as %qE attribute", decl, name); + *no_add_attrs = true; + return NULL_TREE; + } + else if (!is_alias + && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl)) + || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))) + { + error ("weak %q+D cannot be defined %qE", decl, name); + *no_add_attrs = true; + return NULL_TREE; + } + + /* Note that the very first time we process a nested declaration, + decl_function_context will not be set. Indeed, *would* never + be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that + we do below. After such frobbery, pushdecl would set the context. + In any case, this is never what we want. */ + else if (decl_function_context (decl) == 0 && current_function_decl == NULL) + { + tree id; + + id = TREE_VALUE (args); + if (TREE_CODE (id) != STRING_CST) + { + error ("attribute %qE argument not a string", name); + *no_add_attrs = true; + return NULL_TREE; + } + id = get_identifier (TREE_STRING_POINTER (id)); + /* This counts as a use of the object pointed to. */ + TREE_USED (id) = 1; + + if (TREE_CODE (decl) == FUNCTION_DECL) + DECL_INITIAL (decl) = error_mark_node; + else + TREE_STATIC (decl) = 1; + + if (!is_alias) + { + /* ifuncs are also aliases, so set that attribute too. */ + DECL_ATTRIBUTES (decl) + = tree_cons (get_identifier ("alias"), args, + DECL_ATTRIBUTES (decl)); + DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"), + NULL, DECL_ATTRIBUTES (decl)); + } + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + if (decl_in_symtab_p (*node)) + { + struct symtab_node *n = symtab_node::get (decl); + if (n && n->refuse_visibility_changes) + error ("%+qD declared %qs after being used", + decl, is_alias ? "alias" : "ifunc"); + } + + + return NULL_TREE; +} + +/* Handle an "alias" or "ifunc" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_alias_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs); +} + /* (end of attribute-handling). */ /* Language-dependent contents of a type. */ diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index f87351e..84df6c1 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #define INCLUDE_MUTEX +#include "libgccjit.h" #include "system.h" #include "coretypes.h" #include "target.h" @@ -499,6 +500,54 @@ new_param (location *loc, return new param (this, inner); } +const char* fn_attribute_to_string (gcc_jit_fn_attribute attr) +{ + switch (attr) + { + case GCC_JIT_FN_ATTRIBUTE_ALIAS: + return "alias"; + case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE: + return "always_inline"; + case GCC_JIT_FN_ATTRIBUTE_INLINE: + return NULL; + case GCC_JIT_FN_ATTRIBUTE_NOINLINE: + return "noinline"; + case GCC_JIT_FN_ATTRIBUTE_TARGET: + return "target"; + case GCC_JIT_FN_ATTRIBUTE_USED: + return "used"; + case GCC_JIT_FN_ATTRIBUTE_VISIBILITY: + return "visibility"; + case GCC_JIT_FN_ATTRIBUTE_COLD: + return "cold"; + case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE: + return "returns_twice"; + case GCC_JIT_FN_ATTRIBUTE_PURE: + return "pure"; + case GCC_JIT_FN_ATTRIBUTE_CONST: + return "const"; + case GCC_JIT_FN_ATTRIBUTE_WEAK: + return "weak"; + case GCC_JIT_FN_ATTRIBUTE_NONNULL: + return "nonnull"; + case GCC_JIT_FN_ATTRIBUTE_MAX: + return NULL; + } + return NULL; +} + +const char* variable_attribute_to_string (gcc_jit_variable_attribute attr) +{ + switch (attr) + { + case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY: + return "visibility"; + case GCC_JIT_VARIABLE_ATTRIBUTE_MAX: + return NULL; + } + return NULL; +} + /* Construct a playback::function instance. */ playback::function * @@ -509,7 +558,13 @@ new_function (location *loc, const char *name, const auto_vec<param *> *params, int is_variadic, - enum built_in_function builtin_id) + enum built_in_function builtin_id, + const std::vector<gcc_jit_fn_attribute> &attributes, + const std::vector<std::pair<gcc_jit_fn_attribute, + std::string>> &string_attributes, + const std::vector<std::pair<gcc_jit_fn_attribute, + std::vector<int>>> + &int_array_attributes) { int i; param *param; @@ -543,6 +598,8 @@ new_function (location *loc, DECL_RESULT (fndecl) = resdecl; DECL_CONTEXT (resdecl) = fndecl; + tree fn_attributes = NULL_TREE; + if (builtin_id) { gcc_assert (loc == NULL); @@ -588,12 +645,62 @@ new_function (location *loc, DECL_DECLARED_INLINE_P (fndecl) = 1; /* Add attribute "always_inline": */ - DECL_ATTRIBUTES (fndecl) = - tree_cons (get_identifier ("always_inline"), - NULL, - DECL_ATTRIBUTES (fndecl)); + fn_attributes = tree_cons (get_identifier ("always_inline"), + NULL, + fn_attributes); } + /* All attributes need to be declared in `dummy-frontend.cc` and more + specifically in `jit_attribute_table`. */ + for (auto attr: attributes) + { + if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE) + DECL_DECLARED_INLINE_P (fndecl) = 1; + + const char* attribute = fn_attribute_to_string (attr); + if (attribute) + { + tree ident = get_identifier (attribute); + fn_attributes = tree_cons (ident, NULL_TREE, fn_attributes); + } + } + + for (auto attr: string_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + std::string& value = std::get<1>(attr); + tree attribute_value = build_tree_list (NULL_TREE, + ::build_string (value.length () + 1, value.c_str ())); + const char* attribute = fn_attribute_to_string (name); + tree ident = attribute ? get_identifier (attribute) : NULL; + + if (ident) + fn_attributes = tree_cons (ident, attribute_value, fn_attributes); + } + + for (auto attr: int_array_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + std::vector<int>& values = std::get<1>(attr); + + const char* attribute = fn_attribute_to_string (name); + tree ident = attribute ? get_identifier (attribute) : NULL; + + if (!ident) + continue; + + tree tree_list = NULL_TREE; + tree *p_tree_list = &tree_list; + for (auto value : values) + { + tree int_value = build_int_cst (integer_type_node, value); + *p_tree_list = build_tree_list (NULL, int_value); + p_tree_list = &TREE_CHAIN (*p_tree_list); + } + fn_attributes = tree_cons (ident, tree_list, fn_attributes); + } + + decl_attributes (&fndecl, fn_attributes, 0); function *func = new function (this, fndecl, kind); m_functions.safe_push (func); return func; @@ -607,7 +714,9 @@ global_new_decl (location *loc, enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags) + enum global_var_flags flags, + const std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> &attributes) { gcc_assert (type); gcc_assert (name); @@ -652,9 +761,32 @@ global_new_decl (location *loc, if (loc) set_tree_location (inner, loc); + set_variable_string_attribute (attributes, inner); + return inner; } +void +playback:: +set_variable_string_attribute ( + const std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> &string_attributes, + tree decl) +{ + tree var_attributes = NULL_TREE; + for (auto attr: string_attributes) + { + gcc_jit_variable_attribute& name = std::get<0>(attr); + std::string& value = std::get<1>(attr); + tree attribute_value = build_tree_list (NULL_TREE, + ::build_string (value.length () + 1, value.c_str ())); + tree ident = get_identifier (variable_attribute_to_string (name)); + if (ident) + var_attributes = tree_cons (ident, attribute_value, var_attributes); + } + decl_attributes (&decl, var_attributes, 0); +} + /* In use by new_global and new_global_initialized. */ playback::lvalue * @@ -674,10 +806,12 @@ new_global (location *loc, enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags) + enum global_var_flags flags, + const std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> &attributes) { tree inner = - global_new_decl (loc, kind, type, name, flags); + global_new_decl (loc, kind, type, name, flags, attributes); return global_finalize_lvalue (inner); } @@ -818,13 +952,15 @@ playback::context:: new_global_initialized (location *loc, enum gcc_jit_global_kind kind, type *type, - size_t element_size, + size_t element_size, size_t initializer_num_elem, const void *initializer, const char *name, - enum global_var_flags flags) + enum global_var_flags flags, + const std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> &attributes) { - tree inner = global_new_decl (loc, kind, type, name, flags); + tree inner = global_new_decl (loc, kind, type, name, flags, attributes); vec<constructor_elt, va_gc> *constructor_elements = NULL; @@ -1812,7 +1948,9 @@ playback::lvalue * playback::function:: new_local (location *loc, type *type, - const char *name) + const char *name, + const std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> &attributes) { gcc_assert (type); gcc_assert (name); @@ -1825,6 +1963,8 @@ new_local (location *loc, DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr); BIND_EXPR_VARS (m_inner_bind_expr) = inner; + set_variable_string_attribute (attributes, inner); + if (loc) set_tree_location (inner, loc); return new lvalue (m_ctxt, inner); @@ -1947,6 +2087,9 @@ postprocess () current_function_decl = NULL; } + else + /* Add to cgraph to output aliases: */ + rest_of_decl_compilation (m_inner_fndecl, true, 0); } /* Don't leak vec's internal buffer (in non-GC heap) when we are @@ -3365,7 +3508,7 @@ void playback::context:: init_types () { - /* See lto_init() in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc + /* See lto_init () in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc for reference. If TYPE_NAME is not set, debug info will not contain types */ #define NAME_TYPE(t,n) \ if (t) \ diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 9654507..05bafcd 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -21,7 +21,9 @@ along with GCC; see the file COPYING3. If not see #ifndef JIT_PLAYBACK_H #define JIT_PLAYBACK_H +#include <string> #include <utility> // for std::pair +#include <vector> #include "timevar.h" #include "varasm.h" @@ -35,12 +37,21 @@ namespace gcc { namespace jit { +const char* fn_attribute_to_string (gcc_jit_fn_attribute attr); +const char* variable_attribute_to_string (gcc_jit_variable_attribute attr); + /********************************************************************** Playback. **********************************************************************/ namespace playback { +void +set_variable_string_attribute ( + const std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> &attributes, + tree decl); + /* playback::context is an abstract base class. The two concrete subclasses are: @@ -104,14 +115,22 @@ public: const char *name, const auto_vec<param *> *params, int is_variadic, - enum built_in_function builtin_id); + enum built_in_function builtin_id, + const std::vector<gcc_jit_fn_attribute> &attributes, + const std::vector<std::pair<gcc_jit_fn_attribute, + std::string>> &string_attributes, + const std::vector<std::pair<gcc_jit_fn_attribute, + std::vector<int>>> + &int_array_attributes); lvalue * new_global (location *loc, enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags); + enum global_var_flags flags, + const std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> &attributes); lvalue * new_global_initialized (location *loc, @@ -121,7 +140,11 @@ public: size_t initializer_num_elem, const void *initializer, const char *name, - enum global_var_flags flags); + enum global_var_flags flags, + const std::vector<std::pair< + gcc_jit_variable_attribute, + std::string>> + &attributes); rvalue * new_ctor (location *log, @@ -306,7 +329,9 @@ private: enum gcc_jit_global_kind kind, type *type, const char *name, - enum global_var_flags flags); + enum global_var_flags flags, + const std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> &attributes); lvalue * global_finalize_lvalue (tree inner); @@ -500,7 +525,9 @@ public: lvalue * new_local (location *loc, type *type, - const char *name); + const char *name, + const std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> &attributes); block* new_block (const char *name); diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 686c058..6ffadbe 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see #include "jit-builtins.h" #include "jit-recording.h" #include "jit-playback.h" +#include <sstream> namespace gcc { namespace jit { @@ -2068,7 +2069,7 @@ recording::memento::get_debug_string () void recording::memento::write_to_dump (dump &d) { - d.write(" %s\n", get_debug_string ()); + d.write (" %s\n", get_debug_string ()); } /* The implementation of class gcc::jit::recording::string. */ @@ -4026,6 +4027,13 @@ void recording::lvalue::set_alignment (unsigned bytes) m_alignment = bytes; } +void recording::lvalue::add_string_attribute ( + gcc_jit_variable_attribute attribute, + const char* value) +{ + m_string_attributes.push_back (std::make_pair (attribute, std::string (value))); +} + /* The implementation of class gcc::jit::recording::param. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -4102,7 +4110,10 @@ recording::function::function (context *ctxt, m_builtin_id (builtin_id), m_locals (), m_blocks (), - m_fn_ptr_type (NULL) + m_fn_ptr_type (NULL), + m_attributes (), + m_string_attributes (), + m_int_array_attributes () { for (int i = 0; i< num_params; i++) { @@ -4161,7 +4172,10 @@ recording::function::replay_into (replayer *r) m_name->c_str (), ¶ms, m_is_variadic, - m_builtin_id)); + m_builtin_id, + m_attributes, + m_string_attributes, + m_int_array_attributes)); } /* Create a recording::local instance and add it to @@ -4210,6 +4224,40 @@ recording::function::new_block (const char *name) void recording::function::write_to_dump (dump &d) { + for (auto attr: m_attributes) + { + const char* attribute = fn_attribute_to_string (attr); + if (attribute) + d.write ("__attribute(%s)__\n", attribute); + } + for (auto attr: m_string_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + std::string& value = std::get<1>(attr); + const char* attribute = fn_attribute_to_string (name); + + if (attribute) + d.write ("__attribute(%s(\"%s\"))__\n", attribute, value.c_str()); + } + for (auto attr: m_int_array_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + std::vector<int>& values = std::get<1>(attr); + const char* attribute = fn_attribute_to_string (name); + if (attribute) + { + d.write ("__attribute(%s(", attribute); + for (size_t i = 0; i < values.size(); ++i) + { + if (i > 0) + d.write (", %d", values[i]); + else + d.write ("%d", values[i]); + } + d.write ("))__\n"); + } + } + switch (m_kind) { default: gcc_unreachable (); @@ -4404,6 +4452,31 @@ recording::function::get_address (recording::location *loc) return result; } +void +recording::function::add_attribute (gcc_jit_fn_attribute attribute) +{ + m_attributes.push_back (attribute); +} + +void +recording::function::add_string_attribute (gcc_jit_fn_attribute attribute, + const char* value) +{ + m_string_attributes.push_back ( + std::make_pair (attribute, std::string (value))); +} + +void +recording::function::add_integer_array_attribute ( + gcc_jit_fn_attribute attribute, + const int* value, + size_t length) +{ + m_int_array_attributes.push_back (std::make_pair ( + attribute, + std::vector<int> (value, value + length))); +} + /* Implementation of recording::memento::make_debug_string for functions. */ @@ -4425,6 +4498,39 @@ static const char * const names_of_function_kinds[] = { /* Implementation of recording::memento::write_reproducer for functions. */ +static const char * const fn_attribute_reproducer_strings[] = +{ + "GCC_JIT_FN_ATTRIBUTE_ALIAS", + "GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE", + "GCC_JIT_FN_ATTRIBUTE_INLINE", + "GCC_JIT_FN_ATTRIBUTE_NOINLINE", + "GCC_JIT_FN_ATTRIBUTE_TARGET", + "GCC_JIT_FN_ATTRIBUTE_USED", + "GCC_JIT_FN_ATTRIBUTE_VISIBILITY", + "GCC_JIT_FN_ATTRIBUTE_COLD", + "GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE", + "GCC_JIT_FN_ATTRIBUTE_PURE", + "GCC_JIT_FN_ATTRIBUTE_CONST", + "GCC_JIT_FN_ATTRIBUTE_WEAK", + "GCC_JIT_FN_ATTRIBUTE_NONNULL", +}; + +std::string +get_vector_int_debug (std::vector<int> &values) +{ + std::stringstream s; + + s << "{"; + for(auto it = values.begin(); it != values.end(); ++it) + { + if (it != values.begin() ) + s << ", "; + s << *it; + } + s << "}"; + return s.str(); +} + void recording::function::write_reproducer (reproducer &r) { @@ -4467,6 +4573,25 @@ recording::function::write_reproducer (reproducer &r) m_params.length (), params_id, m_is_variadic); + for (auto attribute : m_attributes) + r.write(" gcc_jit_function_add_attribute (%s, %s);\n", + id, + fn_attribute_reproducer_strings[attribute]); + for (auto attribute : m_string_attributes) + r.write(" gcc_jit_function_add_string_attribute (%s, %s, \"%s\");\n", + id, + fn_attribute_reproducer_strings[std::get<0>(attribute)], + std::get<1>(attribute).c_str()); + for (auto attribute : m_int_array_attributes) { + r.write(" gcc_jit_function_add_integer_array_attribute (%s,\n" + " %s,\n" + " (int[])%s,\n" + " %lu);\n", + id, + fn_attribute_reproducer_strings[std::get<0>(attribute)], + get_vector_int_debug (std::get<1>(attribute)).c_str(), + std::get<1>(attribute).size ()); + } } @@ -4879,12 +5004,14 @@ recording::global::replay_into (replayer *r) / m_type->dereference ()->get_size (), m_initializer, playback_string (m_name), - m_flags) + m_flags, + m_string_attributes) : r->new_global (playback_location (r, m_loc), m_kind, m_type->playback_type (), playback_string (m_name), - m_flags); + m_flags, + m_string_attributes); if (m_tls_model != GCC_JIT_TLS_MODEL_NONE) global->set_tls_model (recording::tls_models[m_tls_model]); @@ -4943,6 +5070,15 @@ recording::global::write_to_dump (dump &d) break; } + for (auto attr: m_string_attributes) + { + gcc_jit_variable_attribute& name = std::get<0>(attr); + std::string& value = std::get<1>(attr); + const char* attribute = variable_attribute_to_string (name); + + if (attribute) + d.write ("__attribute(%s(\"%s\"))__\n", attribute, value.c_str()); + } d.write ("%s %s", m_type->get_debug_string (), get_debug_string ()); @@ -5013,6 +5149,10 @@ static const char * const tls_model_enum_strings[] = { "GCC_JIT_TLS_MODEL_LOCAL_EXEC", }; +static const char * const gcc_jit_variable_attribute_enum_strings[] = { + "GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY", +}; + void recording::global::write_reproducer (reproducer &r) { @@ -5042,6 +5182,13 @@ recording::global::write_reproducer (reproducer &r) id, m_link_section->c_str ()); + for (auto attribute : m_string_attributes) + r.write(" gcc_jit_lvalue_add_string_attribute (%s, %s, \"%s\");\n", + id, + gcc_jit_variable_attribute_enum_strings[std::get<0>(attribute)], + std::get<1>(attribute).c_str()); + + if (m_initializer) switch (m_type->dereference ()->get_size ()) { @@ -6622,7 +6769,8 @@ recording::local::replay_into (replayer *r) playback::lvalue *obj = m_func->playback_function () ->new_local (playback_location (r, m_loc), m_type->playback_type (), - playback_string (m_name)); + playback_string (m_name), + m_string_attributes); if (m_reg_name != NULL) obj->set_register_name (m_reg_name->c_str ()); @@ -6644,9 +6792,9 @@ recording::local::write_to_dump (dump &d) { if (d.update_locations ()) m_loc = d.make_location (); - d.write(" %s %s;\n", - m_type->get_debug_string (), - get_debug_string ()); + d.write (" %s %s;\n", + m_type->get_debug_string (), + get_debug_string ()); } void diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index b951c71..cd2e0ad 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -23,6 +23,10 @@ along with GCC; see the file COPYING3. If not see #include "jit-common.h" #include "jit-logging.h" +#include "libgccjit.h" + +#include <string> +#include <vector> class timer; @@ -1216,7 +1220,8 @@ public: m_link_section (NULL), m_reg_name (NULL), m_tls_model (GCC_JIT_TLS_MODEL_NONE), - m_alignment (0) + m_alignment (0), + m_string_attributes () {} playback::lvalue * @@ -1236,8 +1241,12 @@ public: as_rvalue () { return this; } const char *access_as_rvalue (reproducer &r) override; + + void add_string_attribute (gcc_jit_variable_attribute attribute, const char* value); + virtual const char *access_as_lvalue (reproducer &r); virtual bool is_global () const { return false; } + virtual bool is_local () const { return false; } void set_tls_model (enum gcc_jit_tls_model model); void set_link_section (const char *name); void set_register_name (const char *reg_name); @@ -1249,6 +1258,8 @@ protected: string *m_reg_name; enum gcc_jit_tls_model m_tls_model; unsigned m_alignment; + std::vector<std::pair<gcc_jit_variable_attribute, + std::string>> m_string_attributes; }; class param : public lvalue @@ -1342,6 +1353,10 @@ public: rvalue *get_address (location *loc); + void add_attribute (gcc_jit_fn_attribute attribute); + void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value); + void add_integer_array_attribute (gcc_jit_fn_attribute attribute, const int* value, size_t length); + private: string * make_debug_string () final override; void write_reproducer (reproducer &r) final override; @@ -1357,6 +1372,9 @@ private: auto_vec<local *> m_locals; auto_vec<block *> m_blocks; type *m_fn_ptr_type; + std::vector<gcc_jit_fn_attribute> m_attributes; + std::vector<std::pair<gcc_jit_fn_attribute, std::string>> m_string_attributes; + std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> m_int_array_attributes; }; class block : public memento @@ -2086,6 +2104,8 @@ public: void visit_children (rvalue_visitor *) final override {} + bool is_local () const final override { return true; } + void write_to_dump (dump &d) final override; private: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 8ecfe4a..9616f38 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -3965,6 +3965,73 @@ gcc_jit_type_get_aligned (gcc_jit_type *type, return (gcc_jit_type *)type->get_aligned (alignment_in_bytes); } +void +gcc_jit_function_add_attribute (gcc_jit_function *func, + gcc_jit_fn_attribute attribute) +{ + RETURN_IF_FAIL (func, NULL, NULL, "NULL func"); + RETURN_IF_FAIL ((attribute >= 0 && attribute < GCC_JIT_FN_ATTRIBUTE_MAX), + NULL, + NULL, + "attribute should be a `gcc_jit_fn_attribute` enum value"); + + func->add_attribute (attribute); +} + +void +gcc_jit_function_add_string_attribute (gcc_jit_function *func, + gcc_jit_fn_attribute attribute, + const char* value) +{ + RETURN_IF_FAIL (func, NULL, NULL, "NULL func"); + RETURN_IF_FAIL (value, NULL, NULL, "NULL value"); + RETURN_IF_FAIL ((attribute >= 0 && attribute < GCC_JIT_FN_ATTRIBUTE_MAX), + NULL, + NULL, + "attribute should be a `gcc_jit_fn_attribute` enum value"); + + func->add_string_attribute (attribute, value); +} + +/* This function adds an attribute with multiple integer values. For example + `nonnull(1, 2)`. The numbers in `values` are supposed to map how they + should be written in C code. So for `nonnull(1, 2)`, you should pass `1` + and `2` in `values` (and set `length` to `2`). */ +void +gcc_jit_function_add_integer_array_attribute (gcc_jit_function *func, + gcc_jit_fn_attribute attribute, + const int* values, + size_t length) +{ + RETURN_IF_FAIL (func, NULL, NULL, "NULL func"); + RETURN_IF_FAIL (values, NULL, NULL, "NULL values"); + RETURN_IF_FAIL ((attribute >= 0 && attribute < GCC_JIT_FN_ATTRIBUTE_MAX), + NULL, + NULL, + "attribute should be a `gcc_jit_fn_attribute` enum value"); + + func->add_integer_array_attribute (attribute, values, length); +} + +void +gcc_jit_lvalue_add_string_attribute (gcc_jit_lvalue *variable, + gcc_jit_variable_attribute attribute, + const char* value) +{ + RETURN_IF_FAIL (variable, NULL, NULL, "NULL variable"); + RETURN_IF_FAIL (value, NULL, NULL, "NULL value"); + RETURN_IF_FAIL (variable->is_global () || variable->is_local (), + NULL, + NULL, + "variable should be a variable"); + RETURN_IF_FAIL ((attribute >= 0 && attribute < GCC_JIT_VARIABLE_ATTRIBUTE_MAX), + NULL, + NULL, + "attribute should be a `gcc_jit_variable_attribute` enum value"); + + variable->add_string_attribute (attribute, value); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index cbcfabb..235cab0 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1999,6 +1999,61 @@ gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *vector_type); extern gcc_jit_type * gcc_jit_type_unqualified (gcc_jit_type *type); +#define LIBGCCJIT_HAVE_ATTRIBUTES + +/* Function attributes. */ +enum gcc_jit_fn_attribute +{ + GCC_JIT_FN_ATTRIBUTE_ALIAS, + GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE, + GCC_JIT_FN_ATTRIBUTE_INLINE, + GCC_JIT_FN_ATTRIBUTE_NOINLINE, + GCC_JIT_FN_ATTRIBUTE_TARGET, + GCC_JIT_FN_ATTRIBUTE_USED, + GCC_JIT_FN_ATTRIBUTE_VISIBILITY, + GCC_JIT_FN_ATTRIBUTE_COLD, + GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE, + GCC_JIT_FN_ATTRIBUTE_PURE, + GCC_JIT_FN_ATTRIBUTE_CONST, + GCC_JIT_FN_ATTRIBUTE_WEAK, + GCC_JIT_FN_ATTRIBUTE_NONNULL, + + /* Maximum value of this enum, should always be last. */ + GCC_JIT_FN_ATTRIBUTE_MAX, +}; + +/* Add an attribute to a function. */ +extern void +gcc_jit_function_add_attribute (gcc_jit_function *func, + enum gcc_jit_fn_attribute attribute); + +extern void +gcc_jit_function_add_string_attribute (gcc_jit_function *func, + enum gcc_jit_fn_attribute attribute, + const char* value); + +extern void +gcc_jit_function_add_integer_array_attribute ( + gcc_jit_function *func, + enum gcc_jit_fn_attribute attribute, + const int* value, + size_t length); + +/* Variable attributes. */ +enum gcc_jit_variable_attribute +{ + GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY, + + /* Maximum value of this enum, should always be last. */ + GCC_JIT_VARIABLE_ATTRIBUTE_MAX, +}; + +/* Add a string attribute to a variable. */ +extern void +gcc_jit_lvalue_add_string_attribute (gcc_jit_lvalue *variable, + enum gcc_jit_variable_attribute attribute, + const char* value); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index b62f5de..dfb8a9d 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -276,3 +276,11 @@ LIBGCCJIT_ABI_25 { global: gcc_jit_type_get_restrict; } LIBGCCJIT_ABI_24; + +LIBGCCJIT_ABI_26 { + global: + gcc_jit_function_add_attribute; + gcc_jit_function_add_string_attribute; + gcc_jit_lvalue_add_string_attribute; + gcc_jit_function_add_integer_array_attribute; +} LIBGCCJIT_ABI_25; |