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. > > > >> +} > >> + > >> /* 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. > 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. > > > > >> + > >> /* 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). > > > >> 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 > >