@@ -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_counted_by_ref", RID_BUILTIN_COUNTED_BY_REF, D_CONLY },
{ "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 },
{ "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY },
{ "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 },
@@ -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_COUNTED_BY_REF,
RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
/* TS 18661-3 keywords, in the same sequence as the TI_* values. */
@@ -11788,6 +11788,7 @@ names_builtin_p (const char *name)
case RID_BUILTIN_SHUFFLE:
case RID_BUILTIN_SHUFFLEVECTOR:
case RID_BUILTIN_STDC:
+ case RID_BUILTIN_COUNTED_BY_REF:
case RID_CHOOSE_EXPR:
case RID_OFFSETOF:
case RID_TYPES_COMPATIBLE_P:
@@ -10647,6 +10647,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.
@@ -11741,6 +11772,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;
@@ -780,6 +780,7 @@ extern tree composite_type (tree, tree);
extern tree lookup_field (const_tree, tree);
extern tree build_component_ref (location_t, tree, tree, location_t,
location_t, bool = true);
+extern tree handle_counted_by_for_component_ref (location_t, tree);
extern tree build_array_ref (location_t, tree, tree);
extern tree build_omp_array_section (location_t, tree, tree, tree);
extern tree build_external_ref (location_t, tree, bool, tree *);
@@ -2766,6 +2766,27 @@ build_access_with_size_for_counted_by (location_t loc, tree ref,
return call;
}
+/* For the COMPONENT_REF ref, check whether it has a counted_by attribute,
+ if so, wrap this COMPONENT_REF with the corresponding CALL to the
+ function .ACCESS_WITH_SIZE.
+ Otherwise, return the ref itself. */
+
+tree
+handle_counted_by_for_component_ref (location_t loc, tree ref)
+{
+ gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
+ tree datum = TREE_OPERAND (ref, 0);
+ tree subdatum = TREE_OPERAND (ref, 1);
+ tree counted_by_type = NULL_TREE;
+ tree counted_by_ref = build_counted_by_ref (datum, subdatum,
+ &counted_by_type);
+ if (counted_by_ref)
+ ref = build_access_with_size_for_counted_by (loc, ref,
+ counted_by_ref,
+ counted_by_type);
+ return ref;
+}
+
/* Make an expression to refer to the COMPONENT field of structure or
union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the
location of the COMPONENT_REF. COMPONENT_LOC is the location
@@ -2849,13 +2870,9 @@ build_component_ref (location_t loc, tree datum, tree component,
int quals;
tree subtype;
bool use_datum_quals;
- tree counted_by_type = NULL_TREE;
/* Do not handle counted_by when in typeof and alignof operator. */
handle_counted_by = handle_counted_by && !in_typeof && !in_alignof;
- tree counted_by_ref = handle_counted_by
- ? build_counted_by_ref (datum, subdatum,
- &counted_by_type)
- : NULL_TREE;
+
if (TREE_TYPE (subdatum) == error_mark_node)
return error_mark_node;
@@ -2875,10 +2892,8 @@ build_component_ref (location_t loc, tree datum, tree component,
NULL_TREE);
SET_EXPR_LOCATION (ref, loc);
- if (counted_by_ref)
- ref = build_access_with_size_for_counted_by (loc, ref,
- counted_by_ref,
- counted_by_type);
+ if (handle_counted_by)
+ ref = handle_counted_by_for_component_ref (loc, ref);
if (TREE_READONLY (subdatum)
|| (use_datum_quals && TREE_READONLY (datum)))
@@ -15287,6 +15287,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_counted_by_ref (@var{ptr})}
+The built-in function @code{__builtin_counted_by_ref} 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 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.
+
+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_counted_by_ref (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_counted_by_ref (q->array)
+@end smallexample
+
+@noindent
+returns a null pointer to @code{void}.
+
+@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
new file mode 100644
@@ -0,0 +1,135 @@
+/* Test the code generation for the new __builtin_counted_by_ref. */
+/* { 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 MAX(A, B) (A > B) ? (A) : (B)
+#define MY_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 = __builtin_malloc(__size))) { \
+ __builtin_memset(*__p, 0, __size); \
+ __auto_type ret = __builtin_counted_by_ref((*__p)->FAM); \
+ *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \
+ if (sizeof (__builtin_counted_by_ref ((*__p)->FAM)) != sizeof (char *)) \
+ __builtin_abort (); \
+ } \
+})
+
+int count;
+
+int main(int argc, char *argv[])
+{
+ MY_ALLOC(array_annotated, c, 10);
+ if (array_annotated->b != 10)
+ __builtin_abort ();
+ if (__alignof (*__builtin_counted_by_ref (array_annotated->c))
+ != __alignof (array_annotated->b))
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (*__builtin_counted_by_ref (array_annotated->c)),
+ __typeof (array_annotated->b)))
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (char[__builtin_counted_by_ref (array_annotated->c)
+ == &array_annotated->b ? 1 : 10]),
+ __typeof (char[1])))
+ __builtin_abort ();
+
+ MY_ALLOC(array_flex, c, 20);
+ if (array_flex->b == 20)
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (char[__builtin_counted_by_ref (array_flex->c)
+ == &array_flex->b ? 1 : 10]),
+ __typeof (char[10])))
+ __builtin_abort ();
+
+ MY_ALLOC(array_nested_annotated, c, 30);
+ if (array_nested_annotated->b != 30)
+ __builtin_abort ();
+ if (__alignof (*__builtin_counted_by_ref (array_nested_annotated->c))
+ != __alignof (array_nested_annotated->b))
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (*__builtin_counted_by_ref (array_nested_annotated->c)),
+ __typeof (array_nested_annotated->b)))
+ __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 ();
+ if (__alignof (*__builtin_counted_by_ref (annotated_p->c))
+ != __alignof (annotated_p->b))
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (*__builtin_counted_by_ref (annotated_p->c)),
+ __typeof (annotated_p->b)))
+ __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 ();
+ if (__alignof (*__builtin_counted_by_ref (nested_annotated_p->c))
+ != __alignof (nested_annotated_p->b))
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (*__builtin_counted_by_ref (nested_annotated_p->c)),
+ __typeof (nested_annotated_p->b)))
+ __builtin_abort ();
+
+ MY_ALLOC(nested_flex_p, c, count * 4);
+ if (nested_flex_p->b == count * 4)
+ __builtin_abort ();
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,61 @@
+/* Testing the correct usage of the new __builtin_counted_by_ref. */
+/* { 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 MAX(A, B) (A > B) ? (A) : (B)
+#define MY_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 = __builtin_malloc(__size))) { \
+ __builtin_memset(*__p, 0, __size); \
+ __auto_type ret = __builtin_counted_by_ref((*__p)->FAM); \
+ *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \
+ if (sizeof (__builtin_counted_by_ref ((*__p)->FAM)) != sizeof (char *)) \
+ __builtin_abort (); \
+ } \
+})
+
+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_counted_by_ref (); /* { dg-error "wrong number of arguments to" } */
+ __builtin_counted_by_ref (array_annotated->c, 10); /* { dg-error "wrong number of arguments to" } */
+ __builtin_counted_by_ref (array_annotated->other); /* { dg-error "must be an array" } */
+ __builtin_counted_by_ref (foo()); /* { dg-error "must be an array" } */
+
+ return 0;
+}