Hi.We're trying to remove the duplication of the attributes code between the C and libgccjit frontend. The attached patch shows a draft of this attempt that only supports a few attributes. Would that kind of approach be acceptable (I'm not sure since this includes a c-family file in libgccjit)?
If not, do you have any idea of how we could do this? Thanks.
From 320d91cd348f6bb2f2b9dbd7760d63a31f48984e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume1.go...@gmail.com> Date: Sun, 16 Mar 2025 23:34:02 +0100 Subject: [PATCH] Add support for `access` attribute
--- gcc/c-family/c-attribs.cc | 3 +- gcc/c-family/c-common.h | 1 + gcc/jit/dummy-frontend.cc | 69 ++------------------------------------- gcc/jit/jit-playback.cc | 44 +++++++++++++++++++++++++ gcc/jit/jit-playback.h | 4 +++ gcc/jit/jit-recording.cc | 35 ++++++++++++++++++++ gcc/jit/jit-recording.h | 7 ++++ gcc/jit/libgccjit.cc | 38 +++++++++++++++++---- gcc/jit/libgccjit.h | 15 +++++++++ gcc/jit/libgccjit.map | 5 +++ 10 files changed, 147 insertions(+), 74 deletions(-) diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index a1c5d0c895b..29862854724 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -145,7 +145,6 @@ static tree handle_expected_throw_attribute (tree *, tree, tree, int, bool *); static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *); static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, bool *); -static tree handle_access_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 *); @@ -5399,7 +5398,7 @@ append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr, representing a VLA bound. To speed up parsing, the handler transforms the attribute and its arguments into a string. */ -static tree +tree handle_access_attribute (tree node[3], tree name, tree args, int flags, bool *no_add_attrs) { diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index a74530bafff..3a349ed5ae1 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1668,6 +1668,7 @@ extern tree handle_musttail_attribute (tree *, tree, tree, int, bool *); extern bool has_attribute (location_t, tree, tree, tree (*)(tree)); extern tree build_attr_access_from_parms (tree, bool); extern void set_musttail_on_return (tree, location_t, bool); +extern tree handle_access_attribute (tree *, tree, tree, int, bool *); /* In c-format.cc. */ extern bool valid_format_string_type_p (tree); diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc index c93df2e4796..544684356cd 100644 --- a/gcc/jit/dummy-frontend.cc +++ b/gcc/jit/dummy-frontend.cc @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" +#include "c-family/c-common.h" #include "target.h" #include "jit-playback.h" #include "stor-layout.h" @@ -50,13 +51,10 @@ static tree handle_always_inline_attribute (tree *, tree, tree, int, 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_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_novops_attribute (tree *, tree, tree, int, bool *); static tree handle_patchable_function_entry_attribute (tree *, tree, tree, @@ -78,19 +76,6 @@ static tree ignore_attribute (tree *, tree, tree, int, bool *); #define ATTR_EXCL(name, function, type, variable) \ { name, function, type, variable } -/* Define attributes that are mutually exclusive with one another. */ -static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = -{ - ATTR_EXCL ("alloc_align", true, true, true), - ATTR_EXCL ("alloc_size", true, true, true), - ATTR_EXCL ("const", true, true, true), - ATTR_EXCL ("malloc", true, true, true), - ATTR_EXCL ("pure", true, true, true), - ATTR_EXCL ("returns_twice", true, true, true), - ATTR_EXCL ("warn_unused_result", true, true, true), - ATTR_EXCL (NULL, false, false, false), -}; - static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] = { ATTR_EXCL ("noreturn", true, true, true), @@ -158,6 +143,8 @@ static const attribute_spec jit_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ + { "access", 1, 3, false, true, true, false, + handle_access_attribute, NULL }, { "alias", 1, 1, true, false, false, false, handle_alias_attribute, NULL }, { "always_inline", 0, 0, true, false, false, false, @@ -263,30 +250,6 @@ jit_preserve_from_gc (tree t) /* Attribute handlers. */ -/* Handle a "noreturn" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_noreturn_attribute (tree *node, tree ARG_UNUSED (name), - tree ARG_UNUSED (args), int ARG_UNUSED (flags), - bool * ARG_UNUSED (no_add_attrs)) -{ - tree type = TREE_TYPE (*node); - - if (TREE_CODE (*node) == FUNCTION_DECL) - TREE_THIS_VOLATILE (*node) = 1; - 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), - TYPE_READONLY (TREE_TYPE (type)), 1)); - else - gcc_unreachable (); - - return NULL_TREE; -} - /* Handle a "leaf" attribute; arguments as in struct attribute_spec.handler. */ @@ -555,32 +518,6 @@ ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name), return NULL_TREE; } -/* Handle a "format" attribute; arguments as in - struct attribute_spec.handler. */ - -static tree -handle_format_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name), - tree ARG_UNUSED (args), int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - *no_add_attrs = true; - return NULL_TREE; -} - - -/* Handle a "format_arg" attribute; arguments as in - struct attribute_spec.handler. */ - -tree -handle_format_arg_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name), - tree ARG_UNUSED (args), int ARG_UNUSED (flags), - bool *no_add_attrs) -{ - *no_add_attrs = true; - return NULL_TREE; -} - - /* Handle a "fn spec" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 127d435af28..507ada86ce2 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -557,6 +557,16 @@ const char* fn_attribute_to_string (gcc_jit_fn_attribute attr) { switch (attr) { + case GCC_JIT_FN_ATTRIBUTE_ACCESS: + return "access"; + case GCC_JIT_FN_ATTRIBUTE_ACCESS_NONE: + return "none"; + case GCC_JIT_FN_ATTRIBUTE_ACCESS_READ_WRITE: + return "read_write"; + case GCC_JIT_FN_ATTRIBUTE_ACCESS_READ_ONLY: + return "read_only"; + case GCC_JIT_FN_ATTRIBUTE_ACCESS_WRITE_ONLY: + return "write_only"; case GCC_JIT_FN_ATTRIBUTE_ALIAS: return "alias"; case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE: @@ -624,6 +634,10 @@ new_function (location *loc, const std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> &int_array_attributes, + const std::vector<std::tuple<gcc_jit_fn_attribute, + gcc_jit_fn_attribute, + std::vector<int>>> + &sub_attribute_int_array_attributes, bool is_target_builtin) { int i; @@ -770,6 +784,36 @@ new_function (location *loc, fn_attributes = tree_cons (ident, tree_list, fn_attributes); } + for (auto attr: sub_attribute_int_array_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + gcc_jit_fn_attribute& sub_attr = std::get<1>(attr); + std::vector<int>& values = std::get<2>(attr); + + const char* attribute = fn_attribute_to_string (name); + tree ident = attribute ? get_identifier (attribute) : NULL; + + if (!ident) + continue; + + const char* sub_attribute = fn_attribute_to_string (sub_attr); + tree sub_ident = sub_attribute ? get_identifier (sub_attribute) : NULL; + + if (!sub_ident) + continue; + + tree tree_list = build_tree_list (NULL_TREE, sub_ident); + + 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); diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index e5c6c5f81a0..017be211e9f 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -127,6 +127,10 @@ public: const std::vector<std::pair<gcc_jit_fn_attribute, std::vector<int>>> &int_array_attributes, + const std::vector<std::tuple<gcc_jit_fn_attribute, + gcc_jit_fn_attribute, + std::vector<int>>> + &sub_attr_int_array_attributes, bool is_target_builtin); lvalue * diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index a1e88ec8cb2..0953dcccf07 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -4493,6 +4493,7 @@ recording::function::function (context *ctxt, m_attributes (), m_string_attributes (), m_int_array_attributes (), + m_sub_attribute_int_array_attributes (), m_is_target_builtin (is_target_builtin) { for (int i = 0; i< num_params; i++) @@ -4556,6 +4557,7 @@ recording::function::replay_into (replayer *r) m_attributes, m_string_attributes, m_int_array_attributes, + m_sub_attribute_int_array_attributes, m_is_target_builtin)); } @@ -4685,6 +4687,26 @@ recording::function::write_to_dump (dump &d) d.write ("))__\n"); } } + for (auto attr : m_sub_attribute_int_array_attributes) + { + gcc_jit_fn_attribute& name = std::get<0>(attr); + gcc_jit_fn_attribute& sub_attr = std::get<1>(attr); + std::vector<int>& values = std::get<2>(attr); + const char* attribute = fn_attribute_to_string (name); + const char* sub_attribute = fn_attribute_to_string (sub_attr); + if (attribute && sub_attribute) + { + d.write ("__attribute(%s(%s(", attribute, sub_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) { @@ -4913,6 +4935,19 @@ recording::function::add_integer_array_attribute ( std::vector<int> (value, value + length))); } +void +recording::function::add_sub_attribute_integer_array_attribute ( + gcc_jit_fn_attribute attribute, + gcc_jit_fn_attribute sub_attribute, + const int* value, + size_t length) +{ + m_sub_attribute_int_array_attributes.push_back (std::make_tuple ( + attribute, + sub_attribute, + std::vector<int> (value, value + length))); +} + /* Implementation of recording::memento::make_debug_string for functions. */ diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index a496840e172..66f00e0a6e3 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -1611,6 +1611,10 @@ public: 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); + void add_sub_attribute_integer_array_attribute (gcc_jit_fn_attribute attribute, + gcc_jit_fn_attribute sub_attribute, + const int* value, + size_t length); private: string * make_debug_string () final override; @@ -1630,6 +1634,9 @@ private: 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; + std::vector<std::tuple<gcc_jit_fn_attribute, + gcc_jit_fn_attribute, + std::vector<int>>> m_sub_attribute_int_array_attributes; bool m_is_target_builtin; }; diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index 93d8d0cda15..26c1eedde16 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -4373,20 +4373,46 @@ gcc_jit_function_add_string_attribute (gcc_jit_function *func, 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) + 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"); + NULL, + NULL, + "attribute should be a `gcc_jit_fn_attribute` enum value"); func->add_integer_array_attribute (attribute, values, length); } +/* This function adds an attribute with a sub attribute name followed bu + multiple integer values. For example + `access(read_only, 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_sub_attribute_integer_array_attribute (gcc_jit_function *func, + gcc_jit_fn_attribute attribute, + gcc_jit_fn_attribute sub_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"); + RETURN_IF_FAIL ((sub_attribute >= 0 && sub_attribute < GCC_JIT_FN_ATTRIBUTE_MAX), + NULL, + NULL, + "sub_attribute should be a `gcc_jit_fn_attribute` enum value"); + + func->add_sub_attribute_integer_array_attribute (attribute, sub_attribute, values, length); +} + void gcc_jit_lvalue_add_string_attribute (gcc_jit_lvalue *variable, gcc_jit_variable_attribute attribute, diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 12b0f50ff29..d25d98eaabf 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -2173,6 +2173,13 @@ enum gcc_jit_fn_attribute GCC_JIT_FN_ATTRIBUTE_MS_ABI, GCC_JIT_FN_ATTRIBUTE_SYSV_ABI, + GCC_JIT_FN_ATTRIBUTE_ACCESS, + // Acceptable values for access attribute. + GCC_JIT_FN_ATTRIBUTE_ACCESS_NONE, + GCC_JIT_FN_ATTRIBUTE_ACCESS_READ_WRITE, + GCC_JIT_FN_ATTRIBUTE_ACCESS_READ_ONLY, + GCC_JIT_FN_ATTRIBUTE_ACCESS_WRITE_ONLY, + /* Maximum value of this enum, should always be last. */ GCC_JIT_FN_ATTRIBUTE_MAX, }; @@ -2194,6 +2201,14 @@ gcc_jit_function_add_integer_array_attribute ( const int* value, size_t length); +extern void +gcc_jit_function_add_sub_attribute_integer_array_attribute ( + gcc_jit_function *func, + gcc_jit_fn_attribute attribute, + gcc_jit_fn_attribute sub_attribute, + const int* values, + size_t length); + /* Variable attributes. */ enum gcc_jit_variable_attribute { diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 4de16dbe0b9..4bf564142f7 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -373,3 +373,8 @@ LIBGCCJIT_ABI_42 { global: gcc_jit_lvalue_add_attribute; } LIBGCCJIT_ABI_41; + +LIBGCCJIT_ABI_43 { + global: + gcc_jit_function_add_sub_attribute_integer_array_attribute; +} LIBGCCJIT_ABI_42; -- 2.49.0