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

Reply via email to