On Thu, 30 May 2024, Qing Zhao wrote:

> Including the following changes:
> * The definition of the new internal function .ACCESS_WITH_SIZE
>   in internal-fn.def.
> * C FE converts every reference to a FAM with a "counted_by" attribute
>   to a call to the internal function .ACCESS_WITH_SIZE.
>   (build_component_ref in c_typeck.cc)
> 
>   This includes the case when the object is statically allocated and
>   initialized.
>   In order to make this working, the routine digest_init in c-typeck.cc
>   is updated to fold calls to .ACCESS_WITH_SIZE to its first argument
>   when require_constant is TRUE.
> 
>   However, for the reference inside "offsetof", the "counted_by" attribute is
>   ignored since it's not useful at all.
>   (c_parser_postfix_expression in c/c-parser.cc)
> 
>   In addtion to "offsetof", for the reference inside operator "typeof" and
>   "alignof", we ignore counted_by attribute too.
> 
>   When building ADDR_EXPR for the .ACCESS_WITH_SIZE in C FE,
>   replace the call with its first argument.
> 
> * Convert every call to .ACCESS_WITH_SIZE to its first argument.
>   (expand_ACCESS_WITH_SIZE in internal-fn.cc)
> * Provide the utility routines to check the call is .ACCESS_WITH_SIZE and
>   get the reference from the call to .ACCESS_WITH_SIZE.
>   (is_access_with_size_p and get_ref_from_access_with_size in tree.cc)

The middle-end parts of this revised patch are OK.

Thanks,
Richard.

> gcc/c/ChangeLog:
> 
>       * c-parser.cc (c_parser_postfix_expression): Ignore the counted-by
>       attribute when build_component_ref inside offsetof operator.
>       * c-tree.h (build_component_ref): Add one more parameter.
>       * c-typeck.cc (build_counted_by_ref): New function.
>       (build_access_with_size_for_counted_by): New function.
>       (build_component_ref): Check the counted-by attribute and build
>       call to .ACCESS_WITH_SIZE.
>       (build_unary_op): When building ADDR_EXPR for
>         .ACCESS_WITH_SIZE, use its first argument.
>         (lvalue_p): Accept call to .ACCESS_WITH_SIZE.
>       (digest_init): Fold call to .ACCESS_WITH_SIZE to its first
>       argument when require_constant is TRUE.
> 
> gcc/ChangeLog:
> 
>       * internal-fn.cc (expand_ACCESS_WITH_SIZE): New function.
>       * internal-fn.def (ACCESS_WITH_SIZE): New internal function.
>       * tree.cc (is_access_with_size_p): New function.
>       (get_ref_from_access_with_size): New function.
>       * tree.h (is_access_with_size_p): New prototype.
>       (get_ref_from_access_with_size): New prototype.
> 
> gcc/testsuite/ChangeLog:
> 
>       * gcc.dg/flex-array-counted-by-2.c: New test.
> ---
>  gcc/c/c-parser.cc                             |  10 +-
>  gcc/c/c-tree.h                                |   2 +-
>  gcc/c/c-typeck.cc                             | 142 +++++++++++++++++-
>  gcc/internal-fn.cc                            |  34 +++++
>  gcc/internal-fn.def                           |   5 +
>  .../gcc.dg/flex-array-counted-by-2.c          | 112 ++++++++++++++
>  gcc/tree.cc                                   |  22 +++
>  gcc/tree.h                                    |   8 +
>  8 files changed, 328 insertions(+), 7 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/flex-array-counted-by-2.c
> 
> diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
> index 00f8bf4376e5..2d9e9c0969f0 100644
> --- a/gcc/c/c-parser.cc
> +++ b/gcc/c/c-parser.cc
> @@ -10848,9 +10848,12 @@ c_parser_postfix_expression (c_parser *parser)
>           if (c_parser_next_token_is (parser, CPP_NAME))
>             {
>               c_token *comp_tok = c_parser_peek_token (parser);
> +             /* Ignore the counted_by attribute for reference inside
> +                offsetof since the information is not useful at all.  */
>               offsetof_ref
>                 = build_component_ref (loc, offsetof_ref, comp_tok->value,
> -                                      comp_tok->location, UNKNOWN_LOCATION);
> +                                      comp_tok->location, UNKNOWN_LOCATION,
> +                                      false);
>               c_parser_consume_token (parser);
>               while (c_parser_next_token_is (parser, CPP_DOT)
>                      || c_parser_next_token_is (parser,
> @@ -10877,11 +10880,14 @@ c_parser_postfix_expression (c_parser *parser)
>                           break;
>                         }
>                       c_token *comp_tok = c_parser_peek_token (parser);
> +                     /* Ignore the counted_by attribute for reference inside
> +                        offsetof since the information is not useful.  */
>                       offsetof_ref
>                         = build_component_ref (loc, offsetof_ref,
>                                                comp_tok->value,
>                                                comp_tok->location,
> -                                              UNKNOWN_LOCATION);
> +                                              UNKNOWN_LOCATION,
> +                                              false);
>                       c_parser_consume_token (parser);
>                     }
>                   else
> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
> index 531a7e8742e3..56a33b8156c6 100644
> --- a/gcc/c/c-tree.h
> +++ b/gcc/c/c-tree.h
> @@ -779,7 +779,7 @@ extern void mark_exp_read (tree);
>  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);
> +                              location_t, bool = true);
>  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 *);
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index 2375953fdb62..0d9c7a34a0df 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -2584,15 +2584,116 @@ should_suggest_deref_p (tree datum_type)
>      return false;
>  }
>  
> +/* For a SUBDATUM field of a structure or union DATUM, generate a REF to
> +   the object that represents its counted_by per the attribute counted_by
> +   attached to this field if it's a flexible array member field, otherwise
> +   return NULL_TREE.
> +   Set COUNTED_BY_TYPE to the TYPE of the counted_by field.
> +   For example, if:
> +
> +    struct P {
> +      int k;
> +      int x[] __attribute__ ((counted_by (k)));
> +    } *p;
> +
> +    for:
> +    p->x
> +
> +    the ref to the object that represents its element count will be:
> +
> +    &(p->k)
> +
> +*/
> +static tree
> +build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type)
> +{
> +  tree type = TREE_TYPE (datum);
> +  if (!c_flexible_array_member_type_p (TREE_TYPE (subdatum)))
> +    return NULL_TREE;
> +
> +  tree attr_counted_by = lookup_attribute ("counted_by",
> +                                        DECL_ATTRIBUTES (subdatum));
> +  tree counted_by_ref = NULL_TREE;
> +  *counted_by_type = NULL_TREE;
> +  if (attr_counted_by)
> +    {
> +      tree field_id = TREE_VALUE (TREE_VALUE (attr_counted_by));
> +      counted_by_ref
> +     = build_component_ref (UNKNOWN_LOCATION,
> +                            datum, field_id,
> +                            UNKNOWN_LOCATION, UNKNOWN_LOCATION);
> +      counted_by_ref = build_fold_addr_expr (counted_by_ref);
> +
> +      /* Get the TYPE of the counted_by field.  */
> +      tree counted_by_field = lookup_field (type, field_id);
> +      gcc_assert (counted_by_field);
> +
> +      do
> +     {
> +       *counted_by_type = TREE_TYPE (TREE_VALUE (counted_by_field));
> +       counted_by_field = TREE_CHAIN (counted_by_field);
> +     }
> +      while (counted_by_field);
> +    }
> +  return counted_by_ref;
> +}
> +
> +/* Given a COMPONENT_REF REF with the location LOC, the corresponding
> +   COUNTED_BY_REF, and the COUNTED_BY_TYPE, generate an INDIRECT_REF
> +   to a call to the internal function .ACCESS_WITH_SIZE.
> +
> +   REF
> +
> +   to:
> +
> +   (*.ACCESS_WITH_SIZE (REF, COUNTED_BY_REF, 1, (TYPE_OF_SIZE)0, -1))
> +
> +   NOTE: The return type of this function is the POINTER type pointing
> +   to the original flexible array type.
> +   Then the type of the INDIRECT_REF is the original flexible array type.
> +
> +   The type of the first argument of this function is a POINTER type
> +   to the original flexible array type.
> +
> +   The 4th argument of the call is a constant 0 with the TYPE of the
> +   object pointed by COUNTED_BY_REF.
> +
> +  */
> +static tree
> +build_access_with_size_for_counted_by (location_t loc, tree ref,
> +                                    tree counted_by_ref,
> +                                    tree counted_by_type)
> +{
> +  gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref)));
> +  /* The result type of the call is a pointer to the flexible array type.  */
> +  tree result_type = build_pointer_type (TREE_TYPE (ref));
> +
> +  tree call
> +    = build_call_expr_internal_loc (loc, IFN_ACCESS_WITH_SIZE,
> +                                 result_type, 5,
> +                                 array_to_pointer_conversion (loc, ref),
> +                                 counted_by_ref,
> +                                 build_int_cst (integer_type_node, 1),
> +                                 build_int_cst (counted_by_type, 0),
> +                                 build_int_cst (integer_type_node, -1));
> +  /* Wrap the call with an INDIRECT_REF with the flexible array type.  */
> +  call = build1 (INDIRECT_REF, TREE_TYPE (ref), call);
> +  SET_EXPR_LOCATION (call, loc);
> +  return call;
> +}
> +
>  /* 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
>     of COMPONENT.  ARROW_LOC is the location of the first -> operand if
> -   it is from -> operator.  */
> +   it is from -> operator.
> +   If HANDLE_COUNTED_BY is true, check the counted_by attribute and generate
> +   a call to .ACCESS_WITH_SIZE.  Otherwise, ignore the attribute.  */
>  
>  tree
>  build_component_ref (location_t loc, tree datum, tree component,
> -                  location_t component_loc, location_t arrow_loc)
> +                  location_t component_loc, location_t arrow_loc,
> +                  bool handle_counted_by)
>  {
>    tree type = TREE_TYPE (datum);
>    enum tree_code code = TREE_CODE (type);
> @@ -2664,7 +2765,13 @@ 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;
>  
> @@ -2683,6 +2790,12 @@ build_component_ref (location_t loc, tree datum, tree 
> component,
>         ref = build3 (COMPONENT_REF, subtype, datum, subdatum,
>                       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 (TREE_READONLY (subdatum)
>             || (use_datum_quals && TREE_READONLY (datum)))
>           TREE_READONLY (ref) = 1;
> @@ -5087,7 +5200,11 @@ build_unary_op (location_t location, enum tree_code 
> code, tree xarg,
>         goto return_build_unary_op;
>       }
>  
> -      /* Ordinary case; arg is a COMPONENT_REF or a decl.  */
> +      /* Ordinary case; arg is a COMPONENT_REF or a decl, or a call to
> +      .ACCESS_WITH_SIZE.  */
> +      if (is_access_with_size_p (arg))
> +     arg = TREE_OPERAND (TREE_OPERAND (CALL_EXPR_ARG (arg, 0), 0), 0);
> +
>        argtype = TREE_TYPE (arg);
>  
>        /* If the lvalue is const or volatile, merge that into the type
> @@ -5238,6 +5355,9 @@ lvalue_p (const_tree ref)
>      case BIND_EXPR:
>        return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE;
>  
> +    case CALL_EXPR:
> +      return is_access_with_size_p (ref);
> +
>      default:
>        return false;
>      }
> @@ -8525,6 +8645,20 @@ digest_init (location_t init_loc, tree type, tree 
> init, tree origtype,
>  
>    STRIP_TYPE_NOPS (inside_init);
>  
> +  /* If require_constant is TRUE,  when the initializer is a call to
> +     .ACCESS_WITH_SIZE, use the first argument as the initializer.
> +     For example:
> +     y = (char *) .ACCESS_WITH_SIZE ((char *) &static_annotated.c,...)
> +     will be converted to
> +     y = &static_annotated.c.  */
> +
> +  if (require_constant
> +      && TREE_CODE (inside_init) == NOP_EXPR
> +      && TREE_CODE (TREE_OPERAND (inside_init, 0)) == CALL_EXPR
> +      && is_access_with_size_p (TREE_OPERAND (inside_init, 0)))
> +    inside_init
> +      = get_ref_from_access_with_size (TREE_OPERAND (inside_init, 0));
> +
>    if (!c_in_omp_for)
>      {
>        if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR)
> diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
> index 9c09026793fa..eb2c4cd59048 100644
> --- a/gcc/internal-fn.cc
> +++ b/gcc/internal-fn.cc
> @@ -3438,6 +3438,40 @@ expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>      }
>  }
>  
> +/* Expand the IFN_ACCESS_WITH_SIZE function:
> +   ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE, CLASS_OF_SIZE,
> +                  TYPE_OF_SIZE, ACCESS_MODE)
> +   which returns the REF_TO_OBJ same as the 1st argument;
> +
> +   1st argument REF_TO_OBJ: The reference to the object;
> +   2nd argument REF_TO_SIZE: The reference to the size of the object,
> +   3rd argument CLASS_OF_SIZE: The size referenced by the REF_TO_SIZE 
> represents
> +     0: the number of bytes.
> +     1: the number of the elements of the object type;
> +   4th argument TYPE_OF_SIZE: A constant 0 with its TYPE being the same as 
> the TYPE
> +    of the object referenced by REF_TO_SIZE
> +   5th argument ACCESS_MODE:
> +    -1: Unknown access semantics
> +     0: none
> +     1: read_only
> +     2: write_only
> +     3: read_write
> +
> +   Both the return type and the type of the first argument of this
> +   function have been converted from the incomplete array type to
> +   the corresponding pointer type.
> +
> +   For each call to a .ACCESS_WITH_SIZE, replace it with its 1st argument.  
> */
> +
> +static void
> +expand_ACCESS_WITH_SIZE (internal_fn, gcall *stmt)
> +{
> +  tree lhs = gimple_call_lhs (stmt);
> +  tree ref_to_obj = gimple_call_arg (stmt, 0);
> +  if (lhs)
> +    expand_assignment (lhs, ref_to_obj, false);
> +}
> +
>  /* The size of an OpenACC compute dimension.  */
>  
>  static void
> diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
> index 25badbb86e56..8de1fa882e95 100644
> --- a/gcc/internal-fn.def
> +++ b/gcc/internal-fn.def
> @@ -512,6 +512,11 @@ DEF_INTERNAL_FN (PHI, 0, NULL)
>     automatic variable.  */
>  DEF_INTERNAL_FN (DEFERRED_INIT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
>  
> +/* A function to associate the access size and access mode information
> +   with the corresponding reference to an object.  It only reads from the
> +   2nd argument.  */
> +DEF_INTERNAL_FN (ACCESS_WITH_SIZE, ECF_PURE | ECF_LEAF | ECF_NOTHROW, NULL)
> +
>  /* DIM_SIZE and DIM_POS return the size of a particular compute
>     dimension and the executing thread's position within that
>     dimension.  DIM_POS is pure (and not const) so that it isn't
> diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-2.c 
> b/gcc/testsuite/gcc.dg/flex-array-counted-by-2.c
> new file mode 100644
> index 000000000000..d4899a63af3c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-2.c
> @@ -0,0 +1,112 @@
> +/* Test the code generation for the new attribute counted_by.
> +   And also the offsetof operator on such array.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fdump-tree-original" } */
> +
> +#include <stdlib.h>
> +
> +struct annotated {
> +  int b;
> +  char c[] __attribute__ ((counted_by (b)));
> +} *array_annotated;
> +
> +static struct annotated static_annotated = { sizeof "hello", "hello" };
> +static char *y = static_annotated.c;
> +
> +struct flex {
> +  int b;
> +  char c[]; 
> +}; 
> +
> +struct nested_annotated {
> +  struct {
> +    union {
> +      int b;
> +      float f;       
> +    };
> +    int n;
> +  };
> +  char c[] __attribute__ ((counted_by (b)));
> +} *array_nested_annotated;
> +
> +static struct nested_annotated nested_static_annotated
> +                              = { sizeof "hello1", 0, "hello1" };
> +static char *nested_y = nested_static_annotated.c;
> +
> +struct nested_flex {
> +  struct {
> +    union {
> +      int b;
> +      float f;       
> +    };
> +    int n;
> +  };
> +  char c[];
> +};
> +
> +void __attribute__((__noinline__)) setup (int normal_count, int attr_count)
> +{
> +  array_annotated
> +    = (struct annotated *)malloc (sizeof (struct annotated)
> +                               + attr_count *  sizeof (char));
> +  array_annotated->b = attr_count;
> +
> +  array_nested_annotated
> +    = (struct nested_annotated *)malloc (sizeof (struct nested_annotated)
> +                                      + attr_count *  sizeof (char));
> +  array_nested_annotated->b = attr_count;
> +
> +  return;
> +}
> +
> +void __attribute__((__noinline__)) test (char a, char b)
> +{
> +  if (__builtin_offsetof (struct annotated, c[0])
> +      != __builtin_offsetof (struct flex, c[0]))
> +    abort ();
> +  if (__builtin_offsetof (struct annotated, c[1])
> +      != __builtin_offsetof (struct flex, c[1]))
> +    abort ();
> +  if (__builtin_offsetof (struct nested_annotated, c[0]) 
> +      != __builtin_offsetof (struct nested_flex, c[0])) 
> +    abort ();
> +  if (__builtin_offsetof (struct nested_annotated, c[1]) 
> +      != __builtin_offsetof (struct nested_flex, c[1])) 
> +    abort ();
> +
> +  if (__builtin_types_compatible_p (typeof (array_annotated->c),
> +                                 typeof (&(array_annotated->c)[0])))
> +    abort ();
> +  if (__builtin_types_compatible_p (typeof (array_nested_annotated->c),
> +                                 typeof (&(array_nested_annotated->c)[0])))
> +    abort ();
> +
> +  if (__alignof (array_annotated->c) != __alignof (char))
> +    abort ();
> +  if (__alignof (array_nested_annotated->c) != __alignof (char))
> +    abort ();
> +
> +  if ((unsigned long) array_annotated->c != (unsigned long) 
> &array_annotated->c)
> +    abort ();
> +  if ((unsigned long) array_nested_annotated->c
> +       != (unsigned long) &array_nested_annotated->c)
> +    abort ();
> +
> +  array_annotated->c[2] = a;
> +  array_nested_annotated->c[3] = b;
> +
> +  if (y[2] != 'l') abort ();
> +  if (nested_y[4] !='o') abort ();
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +  setup (10,10);   
> +  test ('A', 'B');
> +  if (array_annotated->c[2] != 'A') abort ();
> +  if (array_nested_annotated->c[3] != 'B') abort ();
> +  return 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "ACCESS_WITH_SIZE" 8 "original" } } */
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 6564b002dc1a..01572fe70f72 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -13405,6 +13405,28 @@ component_ref_size (tree ref, special_array_member 
> *sam /* = NULL */)
>         ? NULL_TREE : size_zero_node);
>  }
>  
> +/* Return true if the given node CALL is a call to a .ACCESS_WITH_SIZE
> +   function.  */
> +bool
> +is_access_with_size_p (const_tree call)
> +{
> +  if (TREE_CODE (call) != CALL_EXPR)
> +    return false;
> +  if (CALL_EXPR_IFN (call) == IFN_ACCESS_WITH_SIZE)
> +    return true;
> +  return false;
> +}
> +
> +/* Get the corresponding reference from the call to a .ACCESS_WITH_SIZE.
> + * i.e the first argument of this call.  Return NULL_TREE otherwise.  */
> +tree
> +get_ref_from_access_with_size (tree call)
> +{
> +  if (is_access_with_size_p (call))
> +    return  CALL_EXPR_ARG (call, 0);
> +  return NULL_TREE;
> +}
> +
>  /* Return the machine mode of T.  For vectors, returns the mode of the
>     inner type.  The main use case is to feed the result to HONOR_NANS,
>     avoiding the BLKmode that a direct TYPE_MODE (T) might return.  */
> diff --git a/gcc/tree.h b/gcc/tree.h
> index ee2aae332a41..604885641184 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -5772,6 +5772,14 @@ extern special_array_member component_ref_sam_type 
> (tree);
>     cannot be determined.  */
>  extern tree component_ref_size (tree, special_array_member * = NULL);
>  
> +/* Return true if the given node is a call to a .ACCESS_WITH_SIZE
> +   function.  */
> +extern bool is_access_with_size_p (const_tree);
> +
> +/* Get the corresponding reference from the call to a .ACCESS_WITH_SIZE,
> + * i.e. the first argument of this call.  Return NULL_TREE otherwise.  */
> +extern tree get_ref_from_access_with_size (tree);
> +
>  extern int tree_map_base_eq (const void *, const void *);
>  extern unsigned int tree_map_base_hash (const void *);
>  extern bool tree_map_base_marked_p (const void *);
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to