return expr;
}
-/* Check whether the ARRAY_REF has an counted-by object associated with it
+/* Check whether the REF has an counted-by object associated with it
through the "counted_by" attribute. */
static bool
-has_counted_by_object (tree array_ref)
+has_counted_by_object (tree ref)
{
- /* Currently, only when the array_ref is an indirect_ref to a call to the
- .ACCESS_WITH_SIZE, return true.
+ /* Currently, there are two cases are valid:
+ A. when the ref is an indirect_ref to a call to the
+ .ACCESS_WITH_SIZE, return true. (this is for FAM)
+ B. when the ref is a call to .ACCESS_WITH_SIZE, return true.
+ (this is for pointer field inside a structure)
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)))
+ if ((TREE_CODE (ref) == INDIRECT_REF
+ && is_access_with_size_p (TREE_OPERAND (ref, 0)))
+ || is_access_with_size_p (ref))
return true;
return false;
}
-/* Get the reference to the counted-by object associated with the ARRAY_REF. */
+/* Get the reference to the counted-by object associated with the REF. */
static tree
-get_counted_by_ref (tree array_ref)
+get_counted_by_ref (tree 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.
+ /* Currently, there are two cases are valid:
+ A. when the ref is an indirect_ref to a call to the
+ .ACCESS_WITH_SIZE, return true. (this is for FAM)
+ B. when the ref is a call to .ACCESS_WITH_SIZE, return true.
+ (this is for pointer field inside a structure)
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);
+ if (TREE_CODE (ref) == INDIRECT_REF
+ && is_access_with_size_p (TREE_OPERAND (ref, 0)))
+ return CALL_EXPR_ARG (TREE_OPERAND (ref, 0), 1);
+ else if (is_access_with_size_p (ref))
+ return CALL_EXPR_ARG (ref, 1);
+
return NULL_TREE;
}
e_p = &(*cexpr_list)[0];
tree ref = e_p->value;
- if (TREE_CODE (TREE_TYPE (ref)) != ARRAY_TYPE)
+ if (TREE_CODE (TREE_TYPE (ref)) != ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (ref)) != POINTER_TYPE)
+ {
+ error_at (loc, "the argument to %<__builtin_counted_by_ref%>"
+ " must be an array or pointer");
+ expr.set_error ();
+ break;
+ }
+
+ if (TREE_CODE (ref) != COMPONENT_REF)
{
error_at (loc, "the argument to %<__builtin_counted_by_ref%>"
- " must be an array");
+ " must be a field of a structure");
expr.set_error ();
break;
}
- /* If the array ref is inside TYPEOF or ALIGNOF, the call to
+ /* If the 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 (TREE_CODE (ref) == COMPONENT_REF)
This built-in function is only available in C for now.
-The argument @var{ptr} must be a pointer to an array.
+The argument @var{ptr} must be a pointer to an flexible array or a pointer
+inside a structure.
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.
@} *p;
struct foo2 @{
+ struct bar2 *pointer __attribute__((counted_by (counter2)));
+ int counter2;
+@} *p2;
+
+struct foo3 @{
int other;
- struct bar2 array[];
-@} *q;
+ struct bar3 array[];
+@} *p3;
+
@end smallexample
@noindent
&p->counter with type @code{int *}.
@end smallexample
+@smallexample
+__builtin_counted_by_ref (p2->pointer)
+@end smallexample
+
+@noindent
+returns:
+
+@smallexample
+&p2->counter2 with type @code{int *}.
+@end smallexample
+
+
@noindent
However, the following call to the built-in
@smallexample
-__builtin_counted_by_ref (q->array)
+__builtin_counted_by_ref (p3->array)
@end smallexample
@noindent
--- /dev/null
+/* Testing the correct usage of the new __builtin_counted_by_ref for
+ pointers. */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+#include <stdio.h>
+
+struct annotated {
+ size_t b;
+ int *c __attribute ((counted_by (b)));
+ int other;
+} *p_annotated;
+
+struct flex {
+ size_t b;
+ int *c;
+ int other;
+} *p_flex;
+
+#define MY_ALLOC(P, PA, COUNT) ({ \
+ __auto_type __p = &(P); \
+ __auto_type __c = (COUNT); \
+ size_t __size_1 = (sizeof (*(*__p))); \
+ size_t __size_2 = (sizeof (*((*__p)->PA)) * __c); \
+ if ((*__p = __builtin_malloc (__size_1))) { \
+ __builtin_memset(*__p, 0, __size_1); \
+ (*__p)->PA = __builtin_malloc (__size_2); \
+ __auto_type ret = __builtin_counted_by_ref((*__p)->PA); \
+ *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \
+ if (sizeof (__builtin_counted_by_ref ((*__p)->PA)) != 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(p_annotated, c, 10);
+ MY_ALLOC(p_flex, c, 20);
+ MY_ALLOC(p_annotated, c, c_count);
+ MY_ALLOC(p_flex, c, i_count);
+ MY_ALLOC(p_annotated, c, l_count);
+ MY_ALLOC(p_flex, c, c_count * 3);
+ MY_ALLOC(p_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 (p_annotated->c, 10); /* { dg-error "wrong number of arguments to" } */
+ __builtin_counted_by_ref (p_annotated->other); /* { dg-error "must be an array or pointer" } */
+ __builtin_counted_by_ref (foo()); /* { dg-error "must be a field of a structure" } */
+
+ return 0;
+}
--- /dev/null
+/* Test the code generation for the new __builtin_counted_by_ref
+ for pointers. */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+#include <stdio.h>
+
+struct annotated {
+ int *c __attribute ((counted_by (b)));
+ char b;
+} *p_annotated;
+
+struct flex {
+ int *c;
+ short b;
+} *p_flex;
+
+struct nested_annotated {
+ struct {
+ union {
+ int b;
+ float f;
+ };
+ int n;
+ };
+ char *c __attribute__ ((counted_by (b)));
+} *p_nested_annotated;
+
+struct nested_flex {
+ struct {
+ union {
+ unsigned int b;
+ float f;
+ };
+ int n;
+ };
+ char *c;
+} *p_nested_flex;
+
+#define MY_ALLOC(P, PA, COUNT) ({ \
+ __auto_type __p = &(P); \
+ __auto_type __c = (COUNT); \
+ size_t __size_1 = (sizeof (*(*__p))); \
+ size_t __size_2 = (sizeof (*((*__p)->PA)) * __c); \
+ if ((*__p = __builtin_malloc (__size_1))) { \
+ __builtin_memset(*__p, 0, __size_1); \
+ (*__p)->PA = __builtin_malloc (__size_2); \
+ __auto_type ret = __builtin_counted_by_ref((*__p)->PA); \
+ *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \
+ if (sizeof (__builtin_counted_by_ref ((*__p)->PA)) != sizeof (char *)) \
+ __builtin_abort (); \
+ } \
+})
+
+int count;
+
+int main(int argc, char *argv[])
+{
+ MY_ALLOC(p_annotated, c, 10);
+ if (p_annotated->b != 10)
+ __builtin_abort ();
+ if (__alignof (*__builtin_counted_by_ref (p_annotated->c))
+ != __alignof (p_annotated->b))
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (*__builtin_counted_by_ref (p_annotated->c)),
+ __typeof (p_annotated->b)))
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (char[__builtin_counted_by_ref (p_annotated->c)
+ == &p_annotated->b ? 1 : 10]),
+ __typeof (char[1])))
+ __builtin_abort ();
+
+ MY_ALLOC(p_flex, c, 20);
+ if (p_flex->b == 20)
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (char[__builtin_counted_by_ref (p_flex->c)
+ == &p_flex->b ? 1 : 10]),
+ __typeof (char[10])))
+ __builtin_abort ();
+
+ MY_ALLOC(p_nested_annotated, c, 30);
+ if (p_nested_annotated->b != 30)
+ __builtin_abort ();
+ if (__alignof (*__builtin_counted_by_ref (p_nested_annotated->c))
+ != __alignof (p_nested_annotated->b))
+ __builtin_abort ();
+ if (!__builtin_types_compatible_p
+ (__typeof (*__builtin_counted_by_ref (p_nested_annotated->c)),
+ __typeof (p_nested_annotated->b)))
+ __builtin_abort ();
+
+ MY_ALLOC(p_nested_flex, c, 40);
+ if (p_nested_flex->b == 40)
+ __builtin_abort ();
+
+ count = p_annotated->b * 2 + p_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;
+}
/* 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" } */
+ __builtin_counted_by_ref (array_annotated->other); /* { dg-error "must be an array or pointer" } */
+ __builtin_counted_by_ref (foo()); /* { dg-error "must be a field of a structure" } */
return 0;
}