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 <[email protected]>
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