[v6,2/5] Convert references with "counted_by" attributes to/from .ACCESS_WITH_SIZE.
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 |
success
|
Testing passed
|
Commit Message
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 routines initializer_constant_valid_p_1
and output_constant in varasm.cc are updated to handle calls to
.ACCESS_WITH_SIZE.
(initializer_constant_valid_p_1 and output_constant in varasm.c)
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)
* Adjust alias analysis to exclude the new internal from clobbering anything.
(ref_maybe_used_by_call_p_1 and call_may_clobber_ref_p_1 in tree-ssa-alias.cc)
* Adjust dead code elimination to eliminate the call to .ACCESS_WITH_SIZE when
it's LHS is eliminated as dead code.
(eliminate_unnecessary_stmts in tree-ssa-dce.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)
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.
gcc/ChangeLog:
* internal-fn.cc (expand_ACCESS_WITH_SIZE): New function.
* internal-fn.def (ACCESS_WITH_SIZE): New internal function.
* tree-ssa-alias.cc (ref_maybe_used_by_call_p_1): Special case
IFN_ACCESS_WITH_SIZE.
(call_may_clobber_ref_p_1): Special case IFN_ACCESS_WITH_SIZE.
* tree-ssa-dce.cc (eliminate_unnecessary_stmts): Eliminate the call
to .ACCESS_WITH_SIZE when its LHS is dead.
* tree.cc (process_call_operands): Adjust side effect for function
.ACCESS_WITH_SIZE.
(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.
* varasm.cc (initializer_constant_valid_p_1): Handle call to
.ACCESS_WITH_SIZE.
(output_constant): Handle call to .ACCESS_WITH_SIZE.
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 | 128 +++++++++++++++++-
gcc/internal-fn.cc | 36 +++++
gcc/internal-fn.def | 4 +
.../gcc.dg/flex-array-counted-by-2.c | 112 +++++++++++++++
gcc/tree-ssa-alias.cc | 2 +
gcc/tree-ssa-dce.cc | 5 +-
gcc/tree.cc | 25 +++-
gcc/tree.h | 8 ++
gcc/varasm.cc | 10 ++
11 files changed, 332 insertions(+), 10 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/flex-array-counted-by-2.c
Comments
On 2024-02-16 14:47, 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 routines initializer_constant_valid_p_1
> and output_constant in varasm.cc are updated to handle calls to
> .ACCESS_WITH_SIZE.
> (initializer_constant_valid_p_1 and output_constant in varasm.c)
>
> 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)
> * Adjust alias analysis to exclude the new internal from clobbering anything.
> (ref_maybe_used_by_call_p_1 and call_may_clobber_ref_p_1 in tree-ssa-alias.cc)
> * Adjust dead code elimination to eliminate the call to .ACCESS_WITH_SIZE when
> it's LHS is eliminated as dead code.
> (eliminate_unnecessary_stmts in tree-ssa-dce.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)
>
> 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.
>
> gcc/ChangeLog:
>
> * internal-fn.cc (expand_ACCESS_WITH_SIZE): New function.
> * internal-fn.def (ACCESS_WITH_SIZE): New internal function.
> * tree-ssa-alias.cc (ref_maybe_used_by_call_p_1): Special case
> IFN_ACCESS_WITH_SIZE.
> (call_may_clobber_ref_p_1): Special case IFN_ACCESS_WITH_SIZE.
> * tree-ssa-dce.cc (eliminate_unnecessary_stmts): Eliminate the call
> to .ACCESS_WITH_SIZE when its LHS is dead.
> * tree.cc (process_call_operands): Adjust side effect for function
> .ACCESS_WITH_SIZE.
> (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.
> * varasm.cc (initializer_constant_valid_p_1): Handle call to
> .ACCESS_WITH_SIZE.
> (output_constant): Handle call to .ACCESS_WITH_SIZE.
>
> 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 | 128 +++++++++++++++++-
> gcc/internal-fn.cc | 36 +++++
> gcc/internal-fn.def | 4 +
> .../gcc.dg/flex-array-counted-by-2.c | 112 +++++++++++++++
> gcc/tree-ssa-alias.cc | 2 +
> gcc/tree-ssa-dce.cc | 5 +-
> gcc/tree.cc | 25 +++-
> gcc/tree.h | 8 ++
> gcc/varasm.cc | 10 ++
> 11 files changed, 332 insertions(+), 10 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 c31349dae2ff..a6ed5ac43bb1 100644
> --- a/gcc/c/c-parser.cc
> +++ b/gcc/c/c-parser.cc
> @@ -10850,9 +10850,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,
> @@ -10879,11 +10882,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 c7c23edc4840..59b69ca54f0f 100644
> --- a/gcc/c/c-tree.h
> +++ b/gcc/c/c-tree.h
> @@ -778,7 +778,7 @@ extern void mark_exp_read (tree);
> extern tree composite_type (tree, tree);
> extern tree lookup_field (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 cead0a055068..a29a7d7ec029 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -2546,15 +2546,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;
> +}
Build the second arg, i.e. the address of the counted_by field. OK.
> +
> +/* 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 orignal 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
> + 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);
> @@ -2626,7 +2727,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;
>
> @@ -2645,6 +2752,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;
> @@ -5048,7 +5161,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
> @@ -5195,6 +5312,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;
> }
> diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
> index a07f25f3aee3..331dfe57879b 100644
> --- a/gcc/internal-fn.cc
> +++ b/gcc/internal-fn.cc
> @@ -3393,6 +3393,42 @@ 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: unknown;
> + 1: the number of the elements of the object type;
> + 2: the number of bytes;
Is there value in emitting ACCESS_WITH_SIZE for CLASS_OF_SIZE == 0,
since it'll just be ignored?
> + 4th argument TYPE_OF_SIZE: A constant 0 with the TYPE of the object
> + refed 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);
> + else
> + emit_insn (expand_normal (ref_to_obj));
> +}
> +
> /* The size of an OpenACC compute dimension. */
>
> static void
> diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
> index c14d30365c14..0801c8bfe61d 100644
> --- a/gcc/internal-fn.def
> +++ b/gcc/internal-fn.def
> @@ -510,6 +510,10 @@ 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. */
> +DEF_INTERNAL_FN (ACCESS_WITH_SIZE, 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..84899ae620f3
> --- /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-ssa-alias.cc b/gcc/tree-ssa-alias.cc
> index e7c1c1aa6243..8c070e173bdd 100644
> --- a/gcc/tree-ssa-alias.cc
> +++ b/gcc/tree-ssa-alias.cc
> @@ -2823,6 +2823,7 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> return false;
> case IFN_MASK_STORE_LANES:
> case IFN_MASK_LEN_STORE_LANES:
> + case IFN_ACCESS_WITH_SIZE:
> goto process_args;
> case IFN_MASK_LOAD:
> case IFN_LEN_LOAD:
> @@ -3073,6 +3074,7 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
> case IFN_UBSAN_OBJECT_SIZE:
> case IFN_UBSAN_PTR:
> case IFN_ASAN_CHECK:
> + case IFN_ACCESS_WITH_SIZE:
> return false;
> case IFN_MASK_STORE:
> case IFN_LEN_STORE:
> diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc
> index 636c471d4c89..a54fb1b754dd 100644
> --- a/gcc/tree-ssa-dce.cc
> +++ b/gcc/tree-ssa-dce.cc
> @@ -1459,8 +1459,8 @@ eliminate_unnecessary_stmts (bool aggressive)
> update_stmt (stmt);
> release_ssa_name (name);
>
> - /* GOMP_SIMD_LANE (unless three argument) or ASAN_POISON
> - without lhs is not needed. */
> + /* GOMP_SIMD_LANE (unless three argument), ASAN_POISON
> + or .ACCESS_WITH_SIZE without lhs is not needed. */
> if (gimple_call_internal_p (stmt))
> switch (gimple_call_internal_fn (stmt))
> {
> @@ -1470,6 +1470,7 @@ eliminate_unnecessary_stmts (bool aggressive)
> break;
> /* FALLTHRU */
> case IFN_ASAN_POISON:
> + case IFN_ACCESS_WITH_SIZE:
> remove_dead_stmt (&gsi, bb, to_remove_edges);
> break;
> default:
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 3dff8c510832..18b4e729a5bc 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -4068,7 +4068,8 @@ process_call_operands (tree t)
> int i = call_expr_flags (t);
>
> /* Calls have side-effects, except those to const or pure functions. */
> - if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE)))
> + if ((i & ECF_LOOPING_CONST_OR_PURE)
> + || (!(i & (ECF_CONST | ECF_PURE)) && !is_access_with_size_p (t)))
> side_effects = true;
> /* Propagate TREE_READONLY of arguments for const functions. */
> if (i & ECF_CONST)
> @@ -13362,6 +13363,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 972a067a1f7a..73464d3e3ae3 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -5760,6 +5760,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 *);
> diff --git a/gcc/varasm.cc b/gcc/varasm.cc
> index fa17eff551e8..0e6e44e0420c 100644
> --- a/gcc/varasm.cc
> +++ b/gcc/varasm.cc
> @@ -5082,6 +5082,11 @@ initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache)
> }
> return ret;
>
> + case CALL_EXPR:
> + /* for a call to .ACCESS_WITH_SIZE, check the first argument. */
> + if (tree ref = get_ref_from_access_with_size (value))
> + return initializer_constant_valid_p_1 (ref, endtype, cache);
> + /* FALLTHROUGH. */
> default:
> break;
> }
> @@ -5276,6 +5281,11 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align,
> exp = TREE_OPERAND (exp, 0);
> }
>
> + /* for a call to .ACCESS_WITH_SIZE, check the first argument. */
> + if (TREE_CODE (exp) == CALL_EXPR)
> + if (tree ref = get_ref_from_access_with_size (exp))
> + exp = ref;
> +
> code = TREE_CODE (TREE_TYPE (exp));
> thissize = int_size_in_bytes (TREE_TYPE (exp));
>
> On Mar 11, 2024, at 13:09, Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
>
>
>
> On 2024-02-16 14:47, 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 routines initializer_constant_valid_p_1
>> and output_constant in varasm.cc are updated to handle calls to
>> .ACCESS_WITH_SIZE.
>> (initializer_constant_valid_p_1 and output_constant in varasm.c)
>> 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)
>> * Adjust alias analysis to exclude the new internal from clobbering anything.
>> (ref_maybe_used_by_call_p_1 and call_may_clobber_ref_p_1 in tree-ssa-alias.cc)
>> * Adjust dead code elimination to eliminate the call to .ACCESS_WITH_SIZE when
>> it's LHS is eliminated as dead code.
>> (eliminate_unnecessary_stmts in tree-ssa-dce.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)
>> 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.
>> gcc/ChangeLog:
>> * internal-fn.cc (expand_ACCESS_WITH_SIZE): New function.
>> * internal-fn.def (ACCESS_WITH_SIZE): New internal function.
>> * tree-ssa-alias.cc (ref_maybe_used_by_call_p_1): Special case
>> IFN_ACCESS_WITH_SIZE.
>> (call_may_clobber_ref_p_1): Special case IFN_ACCESS_WITH_SIZE.
>> * tree-ssa-dce.cc (eliminate_unnecessary_stmts): Eliminate the call
>> to .ACCESS_WITH_SIZE when its LHS is dead.
>> * tree.cc (process_call_operands): Adjust side effect for function
>> .ACCESS_WITH_SIZE.
>> (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.
>> * varasm.cc (initializer_constant_valid_p_1): Handle call to
>> .ACCESS_WITH_SIZE.
>> (output_constant): Handle call to .ACCESS_WITH_SIZE.
>> 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 | 128 +++++++++++++++++-
>> gcc/internal-fn.cc | 36 +++++
>> gcc/internal-fn.def | 4 +
>> .../gcc.dg/flex-array-counted-by-2.c | 112 +++++++++++++++
>> gcc/tree-ssa-alias.cc | 2 +
>> gcc/tree-ssa-dce.cc | 5 +-
>> gcc/tree.cc | 25 +++-
>> gcc/tree.h | 8 ++
>> gcc/varasm.cc | 10 ++
>> 11 files changed, 332 insertions(+), 10 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 c31349dae2ff..a6ed5ac43bb1 100644
>> --- a/gcc/c/c-parser.cc
>> +++ b/gcc/c/c-parser.cc
>> @@ -10850,9 +10850,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,
>> @@ -10879,11 +10882,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 c7c23edc4840..59b69ca54f0f 100644
>> --- a/gcc/c/c-tree.h
>> +++ b/gcc/c/c-tree.h
>> @@ -778,7 +778,7 @@ extern void mark_exp_read (tree);
>> extern tree composite_type (tree, tree);
>> extern tree lookup_field (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 cead0a055068..a29a7d7ec029 100644
>> --- a/gcc/c/c-typeck.cc
>> +++ b/gcc/c/c-typeck.cc
>> @@ -2546,15 +2546,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;
>> +}
>
> Build the second arg, i.e. the address of the counted_by field. OK.
>
>> +
>> +/* 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 orignal 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
>> + 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);
>> @@ -2626,7 +2727,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;
>> @@ -2645,6 +2752,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;
>> @@ -5048,7 +5161,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
>> @@ -5195,6 +5312,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;
>> }
>> diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
>> index a07f25f3aee3..331dfe57879b 100644
>> --- a/gcc/internal-fn.cc
>> +++ b/gcc/internal-fn.cc
>> @@ -3393,6 +3393,42 @@ 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: unknown;
>> + 1: the number of the elements of the object type;
>> + 2: the number of bytes;
>
> Is there value in emitting ACCESS_WITH_SIZE for CLASS_OF_SIZE == 0, since it'll just be ignored?
Yes, you are right, looks like there is no need for the “unknown” type.
Maybe it’s better to change this argument as the following:
+ 3rd argument IS_SIZE_NUM_ELEMENTS: TRUE if the size referenced by the REF_TO_SIZE represents
+ the number of the elements of the object type; otherwise, it’s the number of bytes.
Thanks.
Qing
>
>> + 4th argument TYPE_OF_SIZE: A constant 0 with the TYPE of the object
>> + refed 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);
>> + else
>> + emit_insn (expand_normal (ref_to_obj));
>> +}
>> +
>> /* The size of an OpenACC compute dimension. */
>> static void
>> diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
>> index c14d30365c14..0801c8bfe61d 100644
>> --- a/gcc/internal-fn.def
>> +++ b/gcc/internal-fn.def
>> @@ -510,6 +510,10 @@ 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. */
>> +DEF_INTERNAL_FN (ACCESS_WITH_SIZE, 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..84899ae620f3
>> --- /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-ssa-alias.cc b/gcc/tree-ssa-alias.cc
>> index e7c1c1aa6243..8c070e173bdd 100644
>> --- a/gcc/tree-ssa-alias.cc
>> +++ b/gcc/tree-ssa-alias.cc
>> @@ -2823,6 +2823,7 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
>> return false;
>> case IFN_MASK_STORE_LANES:
>> case IFN_MASK_LEN_STORE_LANES:
>> + case IFN_ACCESS_WITH_SIZE:
>> goto process_args;
>> case IFN_MASK_LOAD:
>> case IFN_LEN_LOAD:
>> @@ -3073,6 +3074,7 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
>> case IFN_UBSAN_OBJECT_SIZE:
>> case IFN_UBSAN_PTR:
>> case IFN_ASAN_CHECK:
>> + case IFN_ACCESS_WITH_SIZE:
>> return false;
>> case IFN_MASK_STORE:
>> case IFN_LEN_STORE:
>> diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc
>> index 636c471d4c89..a54fb1b754dd 100644
>> --- a/gcc/tree-ssa-dce.cc
>> +++ b/gcc/tree-ssa-dce.cc
>> @@ -1459,8 +1459,8 @@ eliminate_unnecessary_stmts (bool aggressive)
>> update_stmt (stmt);
>> release_ssa_name (name);
>> - /* GOMP_SIMD_LANE (unless three argument) or ASAN_POISON
>> - without lhs is not needed. */
>> + /* GOMP_SIMD_LANE (unless three argument), ASAN_POISON
>> + or .ACCESS_WITH_SIZE without lhs is not needed. */
>> if (gimple_call_internal_p (stmt))
>> switch (gimple_call_internal_fn (stmt))
>> {
>> @@ -1470,6 +1470,7 @@ eliminate_unnecessary_stmts (bool aggressive)
>> break;
>> /* FALLTHRU */
>> case IFN_ASAN_POISON:
>> + case IFN_ACCESS_WITH_SIZE:
>> remove_dead_stmt (&gsi, bb, to_remove_edges);
>> break;
>> default:
>> diff --git a/gcc/tree.cc b/gcc/tree.cc
>> index 3dff8c510832..18b4e729a5bc 100644
>> --- a/gcc/tree.cc
>> +++ b/gcc/tree.cc
>> @@ -4068,7 +4068,8 @@ process_call_operands (tree t)
>> int i = call_expr_flags (t);
>> /* Calls have side-effects, except those to const or pure functions. */
>> - if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE)))
>> + if ((i & ECF_LOOPING_CONST_OR_PURE)
>> + || (!(i & (ECF_CONST | ECF_PURE)) && !is_access_with_size_p (t)))
>> side_effects = true;
>> /* Propagate TREE_READONLY of arguments for const functions. */
>> if (i & ECF_CONST)
>> @@ -13362,6 +13363,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 972a067a1f7a..73464d3e3ae3 100644
>> --- a/gcc/tree.h
>> +++ b/gcc/tree.h
>> @@ -5760,6 +5760,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 *);
>> diff --git a/gcc/varasm.cc b/gcc/varasm.cc
>> index fa17eff551e8..0e6e44e0420c 100644
>> --- a/gcc/varasm.cc
>> +++ b/gcc/varasm.cc
>> @@ -5082,6 +5082,11 @@ initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache)
>> }
>> return ret;
>> + case CALL_EXPR:
>> + /* for a call to .ACCESS_WITH_SIZE, check the first argument. */
>> + if (tree ref = get_ref_from_access_with_size (value))
>> + return initializer_constant_valid_p_1 (ref, endtype, cache);
>> + /* FALLTHROUGH. */
>> default:
>> break;
>> }
>> @@ -5276,6 +5281,11 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align,
>> exp = TREE_OPERAND (exp, 0);
>> }
>> + /* for a call to .ACCESS_WITH_SIZE, check the first argument. */
>> + if (TREE_CODE (exp) == CALL_EXPR)
>> + if (tree ref = get_ref_from_access_with_size (exp))
>> + exp = ref;
>> +
>> code = TREE_CODE (TREE_TYPE (exp));
>> thissize = int_size_in_bytes (TREE_TYPE (exp));
>>
@@ -10850,9 +10850,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,
@@ -10879,11 +10882,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
@@ -778,7 +778,7 @@ extern void mark_exp_read (tree);
extern tree composite_type (tree, tree);
extern tree lookup_field (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 *);
@@ -2546,15 +2546,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 orignal 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
+ 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);
@@ -2626,7 +2727,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;
@@ -2645,6 +2752,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;
@@ -5048,7 +5161,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
@@ -5195,6 +5312,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;
}
@@ -3393,6 +3393,42 @@ 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: unknown;
+ 1: the number of the elements of the object type;
+ 2: the number of bytes;
+ 4th argument TYPE_OF_SIZE: A constant 0 with the TYPE of the object
+ refed 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);
+ else
+ emit_insn (expand_normal (ref_to_obj));
+}
+
/* The size of an OpenACC compute dimension. */
static void
@@ -510,6 +510,10 @@ 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. */
+DEF_INTERNAL_FN (ACCESS_WITH_SIZE, 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
new file mode 100644
@@ -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" } } */
@@ -2823,6 +2823,7 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
return false;
case IFN_MASK_STORE_LANES:
case IFN_MASK_LEN_STORE_LANES:
+ case IFN_ACCESS_WITH_SIZE:
goto process_args;
case IFN_MASK_LOAD:
case IFN_LEN_LOAD:
@@ -3073,6 +3074,7 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
case IFN_UBSAN_OBJECT_SIZE:
case IFN_UBSAN_PTR:
case IFN_ASAN_CHECK:
+ case IFN_ACCESS_WITH_SIZE:
return false;
case IFN_MASK_STORE:
case IFN_LEN_STORE:
@@ -1459,8 +1459,8 @@ eliminate_unnecessary_stmts (bool aggressive)
update_stmt (stmt);
release_ssa_name (name);
- /* GOMP_SIMD_LANE (unless three argument) or ASAN_POISON
- without lhs is not needed. */
+ /* GOMP_SIMD_LANE (unless three argument), ASAN_POISON
+ or .ACCESS_WITH_SIZE without lhs is not needed. */
if (gimple_call_internal_p (stmt))
switch (gimple_call_internal_fn (stmt))
{
@@ -1470,6 +1470,7 @@ eliminate_unnecessary_stmts (bool aggressive)
break;
/* FALLTHRU */
case IFN_ASAN_POISON:
+ case IFN_ACCESS_WITH_SIZE:
remove_dead_stmt (&gsi, bb, to_remove_edges);
break;
default:
@@ -4068,7 +4068,8 @@ process_call_operands (tree t)
int i = call_expr_flags (t);
/* Calls have side-effects, except those to const or pure functions. */
- if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE)))
+ if ((i & ECF_LOOPING_CONST_OR_PURE)
+ || (!(i & (ECF_CONST | ECF_PURE)) && !is_access_with_size_p (t)))
side_effects = true;
/* Propagate TREE_READONLY of arguments for const functions. */
if (i & ECF_CONST)
@@ -13362,6 +13363,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. */
@@ -5760,6 +5760,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 *);
@@ -5082,6 +5082,11 @@ initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache)
}
return ret;
+ case CALL_EXPR:
+ /* for a call to .ACCESS_WITH_SIZE, check the first argument. */
+ if (tree ref = get_ref_from_access_with_size (value))
+ return initializer_constant_valid_p_1 (ref, endtype, cache);
+ /* FALLTHROUGH. */
default:
break;
}
@@ -5276,6 +5281,11 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align,
exp = TREE_OPERAND (exp, 0);
}
+ /* for a call to .ACCESS_WITH_SIZE, check the first argument. */
+ if (TREE_CODE (exp) == CALL_EXPR)
+ if (tree ref = get_ref_from_access_with_size (exp))
+ exp = ref;
+
code = TREE_CODE (TREE_TYPE (exp));
thissize = int_size_in_bytes (TREE_TYPE (exp));