> On May 29, 2024, at 02:57, Richard Biener <richard.guent...@gmail.com> wrote: > > On Tue, May 28, 2024 at 11:09 PM Qing Zhao <qing.z...@oracle.com> wrote: >> >> Thank you for the comments. See my answers below: >> >> Joseph, please see the last question, I need your help on it. Thanks a lot >> for the help. >> >> Qing >> >>> On May 28, 2024, at 03:38, Richard Biener <richard.guent...@gmail.com> >>> wrote: >>> >>> On Fri, Apr 12, 2024 at 3:54 PM Qing Zhao <qing.z...@oracle.com> 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 | 35 +++++ >>>> 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, 331 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 12fae8591462..402e8f78db2a 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 (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 fb7587f05f1f..ff6685c6c4ba 100644 >>>> --- a/gcc/c/c-typeck.cc >>>> +++ b/gcc/c/c-typeck.cc >>>> @@ -2578,15 +2578,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); >>>> @@ -2658,7 +2759,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; >>>> >>>> @@ -2677,6 +2784,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; >>>> @@ -5080,7 +5193,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 >>>> @@ -5227,6 +5344,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..e744080ee670 100644 >>>> --- a/gcc/internal-fn.cc >>>> +++ b/gcc/internal-fn.cc >>>> @@ -3393,6 +3393,41 @@ 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); >>>> + else >>>> + emit_insn (expand_normal (ref_to_obj)); >>> >>> That looks suspicious, expand_normal does not result in an insn. What is >>> there to do when there's no LHS of the .ACCESS_WITH_SIZE? >> >> I think my initial purpose of that line is trying to handle such rare >> situation that might happen with different optimizations.. >> I can change the else path to a gcc_unreachable() to see any issue. >> What do you think? > > As I've seen later in DCE you happily elide .ACCESS_WITH_SIZE without > a LHS so I'd > say you should simply do nothing (remove the else) here which means > DCEing the call.
Okay, will do that. Thanks. > >>> >>>> +} >>>> + >>>> /* 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) >>> >>> Does .ACCESS_WITH_SIZE store to memory? (or even load?) >> It reads from the 2nd argument. >> So, it’s not PURE. > > If it only reads it _is_ PURE. It's not CONST. Just read the documentation of GCC pure attribute: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute So, ECF_PURE has the same meaning of the pure attribute? If so, yes, .ACCESS_WITH_SIZE is ECF_PURE. Thanks a lot for catching this bug. Will update it. > >> Please see our discussion last November on this: >> https://gcc.gnu.org/pipermail/gcc-patches/2023-November/635158.html >> >> In which: "Although .ACCESS_WITH_SIZE is not PURE anymore, but it’s only >> read from the 2nd argument, and not modify anything in the pointed objects. >> So, we can adjust the IPA alias analysis phase with this details >> (ref_maybe_used_by_call_p_1/call_may_clobber_ref_p_1).” >> >> (NOTE, in the initial proposal >> (https://gcc.gnu.org/pipermail/gcc-patches/2023-October/634844.html) I >> defined it as >> DEF_INTERNAL_FN (ACCESS_WITH_SIZE, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL), >> And later after discussion, we deleted ECF_CONST from it) > > And you now should put in ECF_PURE. Okay. > >> >>> >>>> + >>>> /* 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-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: >>> >>> below you make it not store, so grouping with store IFNs is a bit odd? >>> What's wrong with >>> going through default: for IFN_ACCESS_WITH_SIZE? Does .ACCESS_WITH_SIZE >>> perform a read? How's that represented? >> Yes, it reads from the 2nd argument when used by >> __builtin_dynamic_object_size, or c-ubsan, etc. >> >> .ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE, CLASS_OF_SIZE, SIZE_OF_SIZE, >> ACCESS_MODE, INDEX) >> >> The 2nd argument is the reference to the size of the object (which is the >> field that holds the “counted-by” value in the structure). >> When __builtin_dynamic_object_size queries the size of the object, GCC will >> generate a MEM_REF to the 2nd argument to get the size of the object, please >> see the routine “access_with_size_object_size” in gcc/tree-object-size.cc >> <http://tree-object-size.cc/>. > > But "process_args" doesn't consider that - that only considers aggregate uses. > Your change handles the call like if it were CONST. The default handling > should > be fine here, you shouldn't need to handle .ACCESS_WITH_SIZE in > tree-ssa-alias.cc at all > (if you make it PURE). Yes, marking it as PURE will make the implementation simpler. Thanks a lot. Will update this. Qing > >>> >>>> goto process_a >>>> 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: >>> >>> it doesn't store. So above it should be ECF_PURE at least. >> >> As summarized in >> https://gcc.gnu.org/pipermail/gcc-patches/2023-November/635158.html >> >> ACCESS_WITH_SIZE is not PURE anymore, but it’s only read from the 2nd >> argument, and not modify anything in the pointed objects. > > I think it is. > >> Therefore, I think the change in the above is correct. >> >> i.e: >> /* Treat these internal calls like ECF_PURE for aliasing, >> they don't write to any memory the program should care about. >> They have important other side-effects, and read memory, >> so can't be ECF_NOVOPS. */ >> case IFN_UBSAN_NULL: >> case IFN_UBSAN_BOUNDS: >> case IFN_UBSAN_VPTR: >> case IFN_UBSAN_OBJECT_SIZE: >> case IFN_UBSAN_PTR: >> case IFN_ASAN_CHECK: >> case IFN_ACCESS_WITH_SIZE: >> return false; >> >> What do you think? >> >> >>>> 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: >>> >>> this shouldn't be necessary if you make .ACCESS_WITH_SIZE ECF_PURE >>> (or ECF_CONST if it also doesn't read from memory) >> As explained in the above, .ACCESS_WITH_SIZE is not PURE. >>> >>>> remove_dead_stmt (&gsi, bb, to_remove_edges); >>>> break; >>>> default: >>>> diff --git a/gcc/tree.cc b/gcc/tree.cc >>>> index 3dff8c510832..5fdb425f612a 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))) >>> >>> Err, so why not make it ECF_PURE at least? >> Same above. >>> >>>> 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..fbaef3e5fb5c 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..d75b23668925 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); >>> >>> I think we should fold/strip .ACCESS_WITH_SIZE from initializers >>> instead. That would be >>> the frontends job I guess, most probably not even generate those in >>> the first place? >> >> Sounds reasonable, I will see how to do this in C FE. >> Joseph, do you have any suggestion where in C FE I should do this folding? >> >> thanks. >> >> Qing >>> >>>> + /* 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)); >>>> >>>> -- >>>> 2.31.1