Am Mittwoch, dem 21.08.2024 um 14:12 +0000 schrieb Qing Zhao: ... > > > > > > + if (__builtin_get_counted_by (__p->FAM)) \ > > > + *(__builtin_get_counted_by(__p->FAM)) = COUNT; \ > > > > > > How to improve it? (Thanks a lot for your suggestion). > > > > There's lack of syntactic guarantee that __builtin_get_counted_by (...) != > > 0 is > > a constant expression. __builtin_set_counted_by (...) would avoid this > > when it would be documented to expand to nothing for a type without a > > counted_by > > member.
Does it matter? > > Writing > > > > size_t fake; > > __builtin_choose_expr (__builtin_get_counted_by (__p-->FAM) != 0, > > > > *(__builtin_get_counted_by(__p->FAM)), __fake) = COUNT; > > > > would ensure this but of course requiring the __fake lvalue is ugly, too. > > Yes, you are right. When I wrote the testing case, I felt wield too. (:- > > And another issue with the returned value of __builtin_get_counted_by(PTR) > is, since it returns a pointer, the TYPE of the pointee matters, especially > when returns a NULL pointer, I used a pointer type pointing to the size_t in > case of a NULL pointer being returned to avoid some strict-aliasing issue. > please see PR116316, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116316) for > details. It needs to return a pointer to the actual type of the count field. For NULL, it probably needs to be size_t* for above assignment to work. But if we changed it to return a void pointer, we could make this a compile-time check: auto ret = __builtin_get_counted_by(__p->FAM); _Generic(ret, void*: (void)0, default: *ret = COUNT); > > Yes, I do feel that the approach __builtin_get_counted_by is not very good. > Maybe it’s better to provide > A. __builtin_set_counted_by > or > B. The unary operator __counted_by(PTR) to return a Lvalue, in this case, > we need a __builtin_has_attribute first to check whether PTR has the > counted_by attribute first. You could potentially do the same __counted_by and test for type void. _Generic(typeof(__counted_by(PTR)), void: (void)0, __counted_by(PTR) = COUNT); Martin > > Any suggestion? > > thanks. > > Qing > > > > > > Richard. > > > > > > > > Qing > > > > > > > > > > > No objection to the patch but I wanted to share my thoughts here. > > > > > > > > Richard. > > > > > > > > > Bootstrapped and regression tested on both X86 and aarch64, no issue. > > > > > > > > > > Okay for trunk? > > > > > > > > > > thanks. > > > > > > > > > > Qing. > > > > > > > > > > > > > > > PR c/116016 > > > > > > > > > > gcc/c-family/ChangeLog: > > > > > > > > > > * c-common.cc: Add new __builtin_get_counted_by. > > > > > * c-common.h (enum rid): Add RID_BUILTIN_GET_COUNTED_BY. > > > > > > > > > > gcc/c/ChangeLog: > > > > > > > > > > * c-decl.cc (names_builtin_p): Add RID_BUILTIN_GET_COUNTED_BY. > > > > > * c-parser.cc (has_counted_by_object): New routine. > > > > > (get_counted_by_ref): New routine. > > > > > (c_parser_postfix_expression): Handle New > > > > > RID_BUILTIN_GET_COUNTED_BY. > > > > > > > > > > gcc/ChangeLog: > > > > > > > > > > * doc/extend.texi: Add documentation for > > > > > __builtin_get_counted_by. > > > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > > > * gcc.dg/builtin-get-counted-by-1.c: New test. > > > > > * gcc.dg/builtin-get-counted-by.c: New test. > > > > > --- > > > > > gcc/c-family/c-common.cc | 1 + > > > > > gcc/c-family/c-common.h | 1 + > > > > > gcc/c/c-decl.cc | 1 + > > > > > gcc/c/c-parser.cc | 72 +++++++++++++++ > > > > > gcc/doc/extend.texi | 55 +++++++++++ > > > > > .../gcc.dg/builtin-get-counted-by-1.c | 91 +++++++++++++++++++ > > > > > gcc/testsuite/gcc.dg/builtin-get-counted-by.c | 54 +++++++++++ > > > > > 7 files changed, 275 insertions(+) > > > > > create mode 100644 gcc/testsuite/gcc.dg/builtin-get-counted-by-1.c > > > > > create mode 100644 gcc/testsuite/gcc.dg/builtin-get-counted-by.c > > > > > > > > > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc > > > > > index e7e371fd26f..4b27c6bfeeb 100644 > > > > > --- a/gcc/c-family/c-common.cc > > > > > +++ b/gcc/c-family/c-common.cc > > > > > @@ -430,6 +430,7 @@ const struct c_common_resword c_common_reswords[] > > > > > = > > > > > { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY }, > > > > > { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY }, > > > > > { "__builtin_convertvector", RID_BUILTIN_CONVERTVECTOR, 0 }, > > > > > + { "__builtin_get_counted_by", RID_BUILTIN_GET_COUNTED_BY, D_CONLY > > > > > }, > > > > > { "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 }, > > > > > { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY }, > > > > > { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 }, > > > > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > > > > > index 2510ee4dbc9..5d5a297012f 100644 > > > > > --- a/gcc/c-family/c-common.h > > > > > +++ b/gcc/c-family/c-common.h > > > > > @@ -110,6 +110,7 @@ enum rid > > > > > RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, > > > > > RID_BUILTIN_SHUFFLE, > > > > > RID_BUILTIN_SHUFFLEVECTOR, RID_BUILTIN_CONVERTVECTOR, > > > > > RID_BUILTIN_TGMATH, > > > > > RID_BUILTIN_HAS_ATTRIBUTE, RID_BUILTIN_ASSOC_BARRIER, > > > > > RID_BUILTIN_STDC, > > > > > + RID_BUILTIN_GET_COUNTED_BY, > > > > > RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, > > > > > > > > > > /* TS 18661-3 keywords, in the same sequence as the TI_* values. */ > > > > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc > > > > > index 8cef8f2c289..40bc808878b 100644 > > > > > --- a/gcc/c/c-decl.cc > > > > > +++ b/gcc/c/c-decl.cc > > > > > @@ -11739,6 +11739,7 @@ names_builtin_p (const char *name) > > > > > case RID_BUILTIN_SHUFFLE: > > > > > case RID_BUILTIN_SHUFFLEVECTOR: > > > > > case RID_BUILTIN_STDC: > > > > > + case RID_BUILTIN_GET_COUNTED_BY: > > > > > case RID_CHOOSE_EXPR: > > > > > case RID_OFFSETOF: > > > > > case RID_TYPES_COMPATIBLE_P: > > > > > diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc > > > > > index 9b9284b1ba4..7b179449fb0 100644 > > > > > --- a/gcc/c/c-parser.cc > > > > > +++ b/gcc/c/c-parser.cc > > > > > @@ -10646,6 +10646,35 @@ 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. > > > > > @@ -11740,6 +11769,49 @@ c_parser_postfix_expression (c_parser > > > > > *parser) > > > > > set_c_expr_source_range (&expr, loc, close_paren_loc); > > > > > break; > > > > > } > > > > > + case RID_BUILTIN_GET_COUNTED_BY: > > > > > + { > > > > > + 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_get_counted_by", > > > > > + &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_get_counted_by%>"); > > > > > + expr.set_error (); > > > > > + break; > > > > > + } > > > > > + > > > > > + e_p = &(*cexpr_list)[0]; > > > > > + > > > > > + if (TREE_CODE (TREE_TYPE (e_p->value)) != ARRAY_TYPE) > > > > > + { > > > > > + error_at (loc, "the argument must be an array" > > > > > + "%<__builtin_get_counted_by%>"); > > > > > + expr.set_error (); > > > > > + break; > > > > > + } > > > > > + > > > > > + else if (has_counted_by_object ((*cexpr_list)[0].value)) > > > > > + expr.value > > > > > + = get_counted_by_ref ((*cexpr_list)[0].value); > > > > > + else > > > > > + expr.value > > > > > + = build_int_cst (build_pointer_type (size_type_node), > > > > > 0); > > > > > + > > > > > + set_c_expr_source_range (&expr, loc, close_paren_loc); > > > > > + break; > > > > > + } > > > > > case RID_BUILTIN_SHUFFLE: > > > > > { > > > > > vec<c_expr_t, va_gc> *cexpr_list; > > > > > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > > > > > index 48b27ff9f39..485f6f8dd8d 100644 > > > > > --- a/gcc/doc/extend.texi > > > > > +++ b/gcc/doc/extend.texi > > > > > @@ -15198,6 +15198,61 @@ initializers of variables usable in constant > > > > > expressions. For more details > > > > > refer to the latest revision of the C++ standard. > > > > > @enddefbuiltin > > > > > > > > > > +@defbuiltin{@var{type} __builtin_get_counted_by (@var{ptr})} > > > > > +The built-in function @code{__builtin_get_counted_by} checks whether > > > > > the array > > > > > +object pointed by the pointer @var{ptr} has another object > > > > > associated with it > > > > > +that represents the number of elements in the array object through > > > > > the > > > > > +@code{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 @var{ptr} must be a pointer to an array. > > > > > +The @var{type} of the returned value must be a pointer type pointing > > > > > to the > > > > > +corresponding type of the counted-by object or a pointer type > > > > > pointing to > > > > > +the @var{size_t} in case of a NULL pointer being returned. > > > > > + > > > > > +For example: > > > > > + > > > > > +@smallexample > > > > > +struct foo1 @{ > > > > > + int counter; > > > > > + struct bar1 array[] __attribute__((counted_by (counter))); > > > > > +@} *p; > > > > > + > > > > > +struct foo2 @{ > > > > > + int other; > > > > > + struct bar2 array[]; > > > > > +@} *q; > > > > > +@end smallexample > > > > > + > > > > > +@noindent > > > > > +the following call to the built-in > > > > > + > > > > > +@smallexample > > > > > +__builtin_get_counted_by (p->array) > > > > > +@end smallexample > > > > > + > > > > > +@noindent > > > > > +returns: > > > > > + > > > > > +@smallexample > > > > > +&p->counter with type @code{int *} > > > > > +@end smallexample > > > > > + > > > > > +@noindent > > > > > +However, the following call to the built-in > > > > > + > > > > > +@smallexample > > > > > +__builtin_get_counted_by (q->array) > > > > > +@end smallexample > > > > > + > > > > > +@noindent > > > > > +returns a NULL pointer with type @code{size_t *}. > > > > > + > > > > > +@enddefbuiltin > > > > > + > > > > > @defbuiltin{void __builtin_clear_padding (@var{ptr})} > > > > > The built-in function @code{__builtin_clear_padding} function clears > > > > > padding bits inside of the object representation of object pointed by > > > > > diff --git a/gcc/testsuite/gcc.dg/builtin-get-counted-by-1.c > > > > > b/gcc/testsuite/gcc.dg/builtin-get-counted-by-1.c > > > > > new file mode 100644 > > > > > index 00000000000..fb195f03970 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.dg/builtin-get-counted-by-1.c > > > > > @@ -0,0 +1,91 @@ > > > > > +/* Test the code generation for the new __builtin_get_counted_by. */ > > > > > +/* { dg-do run } */ > > > > > +/* { dg-options "-O2" } */ > > > > > +#include <stdio.h> > > > > > + > > > > > +struct annotated { > > > > > + char b; > > > > > + int c[] __attribute ((counted_by (b))); > > > > > +} *array_annotated; > > > > > + > > > > > +struct flex { > > > > > + short b; > > > > > + int c[]; > > > > > +} *array_flex; > > > > > + > > > > > +struct nested_annotated { > > > > > + struct { > > > > > + union { > > > > > + int b; > > > > > + float f; > > > > > + }; > > > > > + int n; > > > > > + }; > > > > > + char c[] __attribute__ ((counted_by (b))); > > > > > +} *array_nested_annotated; > > > > > + > > > > > +struct nested_flex { > > > > > + struct { > > > > > + union { > > > > > + unsigned int b; > > > > > + float f; > > > > > + }; > > > > > + int n; > > > > > + }; > > > > > + char c[]; > > > > > +} *array_nested_flex; > > > > > + > > > > > +#define MY_ALLOC(P, FAM, COUNT) ({ \ > > > > > + typeof(P) __p; \ > > > > > + size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \ > > > > > + __p = (typeof(P)) __builtin_malloc(__size); \ > > > > > + __builtin_memset(__p, 0, __size); \ > > > > > + if (__builtin_get_counted_by (__p->FAM)) \ > > > > > + *(__builtin_get_counted_by(__p->FAM)) = COUNT; \ > > > > > + P = __p; \ > > > > > +}) > > > > > + > > > > > +int count; > > > > > + > > > > > +int main(int argc, char *argv[]) > > > > > +{ > > > > > + MY_ALLOC(array_annotated, c, 10); > > > > > + if (array_annotated->b != 10) > > > > > + __builtin_abort (); > > > > > + > > > > > + MY_ALLOC(array_flex, c, 20); > > > > > + if (array_flex->b == 20) > > > > > + __builtin_abort (); > > > > > + > > > > > + MY_ALLOC(array_nested_annotated, c, 30); > > > > > + if (array_nested_annotated->b != 30) > > > > > + __builtin_abort (); > > > > > + > > > > > + MY_ALLOC(array_nested_flex, c, 40); > > > > > + if (array_nested_flex->b == 40) > > > > > + __builtin_abort (); > > > > > + > > > > > + count = array_annotated->b * 2 + array_nested_annotated->b * 3; > > > > > + struct annotated * annotated_p; > > > > > + struct flex * flex_p; > > > > > + struct nested_annotated * nested_annotated_p; > > > > > + struct nested_flex * nested_flex_p; > > > > > + > > > > > + MY_ALLOC(annotated_p, c, count); > > > > > + if (annotated_p->b != count) > > > > > + __builtin_abort (); > > > > > + > > > > > + MY_ALLOC(flex_p, c, count * 2); > > > > > + if (flex_p->b == count * 2) > > > > > + __builtin_abort (); > > > > > + > > > > > + MY_ALLOC(nested_annotated_p, c, count * 3); > > > > > + if (nested_annotated_p->b != count * 3) > > > > > + __builtin_abort (); > > > > > + > > > > > + MY_ALLOC(nested_flex_p, c, count * 4); > > > > > + if (nested_flex_p->b == count * 4) > > > > > + __builtin_abort (); > > > > > + > > > > > + return 0; > > > > > +} > > > > > diff --git a/gcc/testsuite/gcc.dg/builtin-get-counted-by.c > > > > > b/gcc/testsuite/gcc.dg/builtin-get-counted-by.c > > > > > new file mode 100644 > > > > > index 00000000000..5eca12bc992 > > > > > --- /dev/null > > > > > +++ b/gcc/testsuite/gcc.dg/builtin-get-counted-by.c > > > > > @@ -0,0 +1,54 @@ > > > > > +/* Testing the correct usage of the new __builtin_get_counted_by. */ > > > > > +/* { dg-do compile } */ > > > > > +/* { dg-options "-O" } */ > > > > > + > > > > > +#include <stdio.h> > > > > > + > > > > > +struct annotated { > > > > > + size_t b; > > > > > + int other; > > > > > + int c[] __attribute ((counted_by (b))); > > > > > +} *array_annotated; > > > > > + > > > > > +struct flex { > > > > > + size_t b; > > > > > + int other; > > > > > + int c[]; > > > > > +} *array_flex; > > > > > + > > > > > +#define MY_ALLOC(P, FAM, COUNT) ({ \ > > > > > + typeof(P) __p; \ > > > > > + size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \ > > > > > + __p = (typeof(P)) __builtin_malloc(__size); \ > > > > > + if (__builtin_get_counted_by (__p->FAM)) \ > > > > > + *(__builtin_get_counted_by(__p->FAM)) = COUNT; \ > > > > > + __p; \ > > > > > +}) > > > > > + > > > > > +extern char c_count; > > > > > +extern short s_count; > > > > > +extern int i_count; > > > > > +extern long l_count; > > > > > +extern float f_count; > > > > > + > > > > > +extern int * foo (); > > > > > + > > > > > +int main(int argc, char *argv[]) > > > > > +{ > > > > > + /* The good usages. */ > > > > > + MY_ALLOC(array_annotated, c, 10); > > > > > + MY_ALLOC(array_flex, c, 20); > > > > > + MY_ALLOC(array_annotated, c, c_count); > > > > > + MY_ALLOC(array_flex, c, i_count); > > > > > + MY_ALLOC(array_annotated, c, l_count); > > > > > + MY_ALLOC(array_flex, c, c_count * 3); > > > > > + MY_ALLOC(array_annotated, c, l_count * i_count); > > > > > + > > > > > + /* The bad usages, issue errors. */ > > > > > + __builtin_get_counted_by (); /* { dg-error "wrong number of > > > > > arguments to" } */ > > > > > + __builtin_get_counted_by (array_annotated->c, 10); /* { dg-error > > > > > "wrong number of arguments to" } */ > > > > > + __builtin_get_counted_by (array_annotated->other); /* { dg-error > > > > > "the argument must be an array" } */ > > > > > + __builtin_get_counted_by (foo()); /* { dg-error "the argument > > > > > must be an array" } */ > > > > > + > > > > > + return 0; > > > > > +} > > > > > -- > > > > > 2.31.1 > > -- Univ.-Prof. Dr. rer. nat. Martin Uecker Graz University of Technology Institute of Biomedical Imaging