aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.cc
diff options
context:
space:
mode:
authorQing Zhao <qing.zhao@oracle.com>2024-10-15 17:55:22 +0000
committerQing Zhao <qing.zhao@oracle.com>2024-10-15 19:55:54 +0000
commite7380688fa5917011c3fb85b5e06fb00f776a95d (patch)
tree7c12cb6c211b051e63f7d260ba9f9da1e968cbc6 /gcc/c/c-parser.cc
parent50f27896adb272b40ab03a56fd192e74789bef97 (diff)
downloadgcc-e7380688fa5917011c3fb85b5e06fb00f776a95d.zip
gcc-e7380688fa5917011c3fb85b5e06fb00f776a95d.tar.gz
gcc-e7380688fa5917011c3fb85b5e06fb00f776a95d.tar.bz2
Provide new GCC builtin __builtin_counted_by_ref [PR116016]
With the addition of the 'counted_by' attribute and its wide roll-out within the Linux kernel, a use case has been found that would be very nice to have for object allocators: being able to set the counted_by counter variable without knowing its name. For example, given: struct foo { ... int counter; ... struct bar array[] __attribute__((counted_by (counter))); } *p; The existing Linux object allocators are roughly: #define MAX(A, B) (A > B) ? (A) : (B) #define alloc(P, FAM, COUNT) ({ \ __auto_type __p = &(P); \ size_t __size = MAX (sizeof(*P), __builtin_offsetof (__typeof(*P), FAM) + sizeof (*(P->FAM)) * COUNT); \ *__p = kmalloc(__size); \ }) Right now, any addition of a counted_by annotation must also include an open-coded assignment of the counter variable after the allocation: p = alloc(p, array, how_many); p->counter = how_many; In order to avoid the tedious and error-prone work of manually adding the open-coded counted-by intializations everywhere in the Linux kernel, a new GCC builtin __builtin_counted_by_ref will be very useful to be added to help the adoption of the counted-by attribute. -- Built-in Function: TYPE __builtin_counted_by_ref (PTR) The built-in function '__builtin_counted_by_ref' checks whether the array object pointed by the pointer PTR has another object associated with it that represents the number of elements in the array object through the 'counted_by' attribute (i.e. the counted-by object). If so, returns a pointer to the corresponding counted-by object. If such counted-by object does not exist, returns a null pointer. This built-in function is only available in C for now. The argument PTR must be a pointer to an array. The TYPE of the returned value is a pointer type pointing to the corresponding type of the counted-by object or a void pointer type in case of a null pointer being returned. With this new builtin, the central allocator could be updated to: #define MAX(A, B) (A > B) ? (A) : (B) #define alloc(P, FAM, COUNT) ({ \ __auto_type __p = &(P); \ __auto_type __c = (COUNT); \ size_t __size = MAX (sizeof (*(*__p)),\ __builtin_offsetof (__typeof(*(*__p)),FAM) \ + sizeof (*((*__p)->FAM)) * __c); \ if ((*__p = kmalloc(__size))) { \ __auto_type ret = __builtin_counted_by_ref((*__p)->FAM); \ *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \ } \ }) And then structs can gain the counted_by attribute without needing additional open-coded counter assignments for each struct, and unannotated structs could still use the same allocator. PR c/116016 gcc/c-family/ChangeLog: * c-common.cc: Add new __builtin_counted_by_ref. * c-common.h (enum rid): Add RID_BUILTIN_COUNTED_BY_REF. gcc/c/ChangeLog: * c-decl.cc (names_builtin_p): Add RID_BUILTIN_COUNTED_BY_REF. * c-parser.cc (has_counted_by_object): New routine. (get_counted_by_ref): New routine. (c_parser_postfix_expression): Handle New RID_BUILTIN_COUNTED_BY_REF. * c-tree.h: New routine handle_counted_by_for_component_ref. * c-typeck.cc (handle_counted_by_for_component_ref): New routine. (build_component_ref): Call the new routine. gcc/ChangeLog: * doc/extend.texi: Add documentation for __builtin_counted_by_ref. gcc/testsuite/ChangeLog: * gcc.dg/builtin-counted-by-ref-1.c: New test. * gcc.dg/builtin-counted-by-ref.c: New test.
Diffstat (limited to 'gcc/c/c-parser.cc')
-rw-r--r--gcc/c/c-parser.cc79
1 files changed, 79 insertions, 0 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 0ffbdc7..0834f8c 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10781,6 +10781,37 @@ c_parser_predefined_identifier (c_parser *parser)
return expr;
}
+/* Check whether the ARRAY_REF has an counted-by object associated with it
+ through the "counted_by" attribute. */
+
+static bool
+has_counted_by_object (tree array_ref)
+{
+ /* Currently, only when the array_ref is an indirect_ref to a call to the
+ .ACCESS_WITH_SIZE, return true.
+ More cases can be included later when the counted_by attribute is
+ extended to other situations. */
+ if (TREE_CODE (array_ref) == INDIRECT_REF
+ && is_access_with_size_p (TREE_OPERAND (array_ref, 0)))
+ return true;
+ return false;
+}
+
+/* Get the reference to the counted-by object associated with the ARRAY_REF. */
+
+static tree
+get_counted_by_ref (tree array_ref)
+{
+ /* Currently, only when the array_ref is an indirect_ref to a call to the
+ .ACCESS_WITH_SIZE, get the corresponding counted_by ref.
+ More cases can be included later when the counted_by attribute is
+ extended to other situations. */
+ if (TREE_CODE (array_ref) == INDIRECT_REF
+ && is_access_with_size_p (TREE_OPERAND (array_ref, 0)))
+ return CALL_EXPR_ARG (TREE_OPERAND (array_ref, 0), 1);
+ return NULL_TREE;
+}
+
/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2,
C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to
call c_parser_postfix_expression_after_paren_type on encountering them.
@@ -11875,6 +11906,54 @@ c_parser_postfix_expression (c_parser *parser)
set_c_expr_source_range (&expr, loc, close_paren_loc);
break;
}
+ case RID_BUILTIN_COUNTED_BY_REF:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ c_expr_t *e_p;
+ location_t close_paren_loc;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_counted_by_ref",
+ &cexpr_list, false,
+ &close_paren_loc))
+ {
+ expr.set_error ();
+ break;
+ }
+ if (vec_safe_length (cexpr_list) != 1)
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_counted_by_ref%>");
+ expr.set_error ();
+ break;
+ }
+
+ e_p = &(*cexpr_list)[0];
+ tree ref = e_p->value;
+
+ if (TREE_CODE (TREE_TYPE (ref)) != ARRAY_TYPE)
+ {
+ error_at (loc, "the argument to %<__builtin_counted_by_ref%>"
+ " must be an array");
+ expr.set_error ();
+ break;
+ }
+
+ /* If the array ref is inside TYPEOF or ALIGNOF, the call to
+ .ACCESS_WITH_SIZE was not generated by the routine
+ build_component_ref by default, we should generate it here. */
+ if ((in_typeof || in_alignof) && TREE_CODE (ref) == COMPONENT_REF)
+ ref = handle_counted_by_for_component_ref (loc, ref);
+
+ if (has_counted_by_object (ref))
+ expr.value = get_counted_by_ref (ref);
+ else
+ expr.value = null_pointer_node;
+
+ set_c_expr_source_range (&expr, loc, close_paren_loc);
+ break;
+ }
case RID_BUILTIN_SHUFFLE:
{
vec<c_expr_t, va_gc> *cexpr_list;