diff options
author | Qing Zhao <qing.zhao@oracle.com> | 2024-10-15 17:55:22 +0000 |
---|---|---|
committer | Qing Zhao <qing.zhao@oracle.com> | 2024-10-15 19:55:54 +0000 |
commit | e7380688fa5917011c3fb85b5e06fb00f776a95d (patch) | |
tree | 7c12cb6c211b051e63f7d260ba9f9da1e968cbc6 /gcc/c/c-parser.cc | |
parent | 50f27896adb272b40ab03a56fd192e74789bef97 (diff) | |
download | gcc-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.cc | 79 |
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; |