> Hi Cupertino,
>
> On 2/19/26 12:38, Cupertino Miranda wrote:
>> Hi everyone,
>> 
>> This is v4. This patch goes one step further and simplifies how the
>> expressions are converted to CO-RE in the case where
>> explicit expressions should be converted, i.e. no
>> builtin_preserve_access_index is used.
>> Since the expression split separates CO-RE expressions from non CO-RE
>> expressions it also allowed to simplify the walker that creates the
>> internal core_builtin calls.
>
> Overall this version is looking quite nice.
> Just a couple of notes inline below.
> Thanks!
>
>> 
>> This is a delta between the before and after of the patch.
>> 
>> # diff /tmp/baseline.txt /tmp/new.txt 
>> 155c155
>> < #35/15   bpf_tcp_ca/cc_cubic:FAIL
>> ---
>>> #35/15   bpf_tcp_ca/cc_cubic:OK
>> 157c157
>> < #35      bpf_tcp_ca:FAIL
>> ---
>>> #35      bpf_tcp_ca:OK
>> 1166c1166
>> < #109/5   fd_array_cnt/fd-array-ref-btfs:FAIL
>> ---
>>> #109/5   fd_array_cnt/fd-array-ref-btfs:OK
>> 1169c1169
>> < #109     fd_array_cnt:FAIL
>> ---
>>> #109     fd_array_cnt:OK
>> 1686c1686
>> < #189/1   lsm_cgroup/functional:FAIL
>> ---
>>> #189/1   lsm_cgroup/functional:OK
>> 1688c1688
>> < #189     lsm_cgroup:FAIL
>> ---
>>> #189     lsm_cgroup:OK
>> 4155,4159c4155,4159
>> < #546/1   verifier_bitfield_write/single CO-RE bitfield roundtrip:FAIL
>> < #546/2   verifier_bitfield_write/multiple CO-RE bitfield roundtrip:FAIL
>> < #546/3   verifier_bitfield_write/adjacent CO-RE bitfield roundtrip:FAIL
>> < #546/4   verifier_bitfield_write/multibyte CO-RE bitfield roundtrip:FAIL
>> < #546     verifier_bitfield_write:FAIL
>> ---
>>> #546/1   verifier_bitfield_write/single CO-RE bitfield roundtrip:OK
>>> #546/2   verifier_bitfield_write/multiple CO-RE bitfield roundtrip:OK
>>> #546/3   verifier_bitfield_write/adjacent CO-RE bitfield roundtrip:OK
>>> #546/4   verifier_bitfield_write/multibyte CO-RE bitfield roundtrip:OK
>>> #546     verifier_bitfield_write:OK
>
> Very good.
>
>> 
>> Looking forward to your review.
>> 
>> Thanks,
>> Cupertino
>> 
>> ---------
>> 
>> This patch corrects CO-RE generation for the cases where an expression
>> starts with a non-CO-RE access, but in the middle it requires to
>> generate CO-RE to correctly compute the access location.
>> 
>> It fixes it by splitting the expression into their CO-RE and non-CO-RE
>> counterparts. It performs this by walking gimple expressions, and for
>> each field access to which its type is a struct or union, it verifies if
>> both the types for the base and field are attributed similarly.
>> Otherwise, it splits the expression at this location by creating a
>> temporary variable and performing any required pointer conversions.
>> This smaller expressions are converted to CO-RE in the subsequent
>> gimple walker.
>> 
>> There is no way in GCC to distinguish nested struct/union definitions
>> from non-nested ones.
>> This patch simplifies code and enforces that all preserve_access_index
>> structs/unions would be attributed explicitly.
>> Previous approach was error prone as it would extend CO-RE accesses to
>> structures which would not be attributed.
>> 
>> All GCC BPF dejagnu passes tests:
>>   # of expected passes               553
>>   # of expected failures             6
>> 
>> kernel-next bpf selftests:
>>  before: Summary: 543/4888 PASSED, 113 SKIPPED, 136 FAILED
>>  after:  Summary: 545/4893 PASSED, 113 SKIPPED, 134 FAILED
>> 
>> gcc/ChangeLog:
>>      PR target/120241
>>      * config/bpf/core-builtins.cc
>>      (is_attr_preserve_access): Correct for pointer types.
>>      (maybe_get_base_for_field_expr, core_access_index_map,
>>      core_access_clean, core_is_access_index, core_mark_as_access_index):
>>      Remove.
>>      (make_gimple_core_safe_access_index): Remove function.
>>      (struct walker_data): New struct to pass data to tree walker.
>>      (callback_should_do_core_access, should_do_core_access): Add
>>      function to identify expressions that should not be converted to
>>      CO-RE.
>>      (core_make_builtins): Add callback tree walker function to
>>      convert expressions to CO-RE.
>>      (callback_find_next_split_location, core_should_split_expr,
>>      find_next_split_location, gimple_core_early_split_expr): Add
>>      function to split expressions in CO-RE and non-CO-RE
>>      expressions.
>>      (execute_lower_bpf_core): Adapt to new code.
>> 
>> gcc/testsuite/ChangeLog:
>>      PR target/120241
>>      * gcc.target/bpf/core-attr-3.c: Add attribute.
>>      * gcc.target/bpf/core-attr-4.c: Add attribute.
>>      * gcc.target/bpf/core-attr-5.c: Add attribute.
>>      * gcc.target/bpf/core-attr-6.c: Add attribute.
>>      * gcc.target/bpf/core-attr-7.c: New test.
>>      * gcc.target/bpf/core-attr-calls.c: Adapt.
>> ---
>>  gcc/config/bpf/bpf.opt                        |   4 +
>>  gcc/config/bpf/core-builtins.cc               | 306 ++++++++++++------
>>  gcc/testsuite/gcc.target/bpf/core-attr-3.c    |   4 +-
>>  gcc/testsuite/gcc.target/bpf/core-attr-4.c    |   4 +-
>>  gcc/testsuite/gcc.target/bpf/core-attr-5.c    |   2 +-
>>  gcc/testsuite/gcc.target/bpf/core-attr-6.c    |   4 +-
>>  gcc/testsuite/gcc.target/bpf/core-attr-7.c    | 150 +++++++++
>>  .../gcc.target/bpf/core-attr-calls.c          |   4 +-
>>  8 files changed, 371 insertions(+), 107 deletions(-)
>>  create mode 100644 gcc/testsuite/gcc.target/bpf/core-attr-7.c
>> 
>> diff --git a/gcc/config/bpf/bpf.opt b/gcc/config/bpf/bpf.opt
>> index 54d038a7fdea..fe34b18c19d6 100644
>> --- a/gcc/config/bpf/bpf.opt
>> +++ b/gcc/config/bpf/bpf.opt
>> @@ -112,3 +112,7 @@ Enum(asm_dialect) String(pseudoc) Value(ASM_PSEUDOC)
>>  minline-memops-threshold=
>>  Target RejectNegative Joined UInteger Var(bpf_inline_memops_threshold) 
>> Init(1024)
>>  -minline-memops-threshold=<number> Maximum size of memset/memmove/memcpy to 
>> inline, larger sizes will use a library call.
>> +
>> +Wbpf-core
>> +Target Warning
>> +Warn when CO-RE support is not guaranteed.
>
> I like this new warning option.
>
> But it needs a corresponding entry and documentation in doc/invoke.texi
> under the BPF Options.

And please then remember to regenerate bpf.opt.urls (which I always
forget)... :)

>
>
>> diff --git a/gcc/config/bpf/core-builtins.cc 
>> b/gcc/config/bpf/core-builtins.cc
>> index 152da94a9761..cf32fe08a3f5 100644
>> --- a/gcc/config/bpf/core-builtins.cc
>> +++ b/gcc/config/bpf/core-builtins.cc
>> @@ -324,8 +324,13 @@ is_attr_preserve_access (tree t)
>>                           TYPE_ATTRIBUTES (TREE_TYPE (base)));
>>  
>>    if (TREE_CODE (base) == MEM_REF)
>> -    return lookup_attribute ("preserve_access_index",
>> -                         TYPE_ATTRIBUTES (TREE_TYPE (base)));
>> +    {
>> +      tree type = TREE_TYPE (base);
>> +      if (POINTER_TYPE_P (type))
>> +    type = TREE_TYPE (type);
>> +      return lookup_attribute ("preserve_access_index",
>> +                           TYPE_ATTRIBUTES (type));
>> +    }
>>  
>>    if (TREE_CODE (t) == COMPONENT_REF)
>>      {
>> @@ -1710,137 +1715,241 @@ bpf_output_core_reloc (rtx *operands, int nr_ops)
>>      }
>>  }
>>  
>> +/* This function verifies if the passed tree node t is a struct field
>> +   expression and if at this location is is necessary to break the 
>> expression
>> +   in order to split CO-RE and non CO-RE required field/union accesses.  */
>> +
>> +static bool
>> +core_should_split_expr (tree t)
>> +{
>> +  tree type = TREE_TYPE (t);
>> +  if (TREE_CODE (type) != RECORD_TYPE
>> +      && TREE_CODE (type) != UNION_TYPE)
>> +    return false;
>> +
>> +  if (TREE_CODE (t) == COMPONENT_REF)
>> +    {
>> +      tree base = TREE_OPERAND (t, 0);
>> +
>> +      bool base_is_attr = lookup_attribute ("preserve_access_index",
>> +                         TYPE_ATTRIBUTES (TREE_TYPE (base))) != NULL_TREE;
>> +      bool cur_is_attr = lookup_attribute ("preserve_access_index",
>> +                         TYPE_ATTRIBUTES (TREE_TYPE (t))) != NULL_TREE;
>> +
>> +      if (base_is_attr != cur_is_attr)
>> +    return true;
>> +    }
>> +  return false;
>> +}
>> +
>> +struct walker_data {
>> +  bool is_root;
>> +  tree *core_base_pointer;
>> +};
>> +
>>  static tree
>> -maybe_get_base_for_field_expr (tree expr)
>> +callback_find_next_split_location (tree *tp,
>> +                               int *walk_subtrees ATTRIBUTE_UNUSED,
>> +                               void *data)
>>  {
>> -  poly_int64 bitsize, bitpos;
>> -  tree var_off;
>> -  machine_mode mode;
>> -  int sign, reverse, vol;
>> +  struct walker_data *d = (struct walker_data *) data;
>>  
>> -  if (expr == NULL_TREE)
>> +  if (d->is_root == true && TREE_CODE (*tp) == ADDR_EXPR)
>>      return NULL_TREE;
>>  
>> -  return get_inner_reference (expr, &bitsize, &bitpos, &var_off, &mode,
>> -                          &sign, &reverse, &vol);
>> +  if (d->is_root == false && core_should_split_expr (*tp))
>> +    {
>> +      d->core_base_pointer = tp;
>> +      return *tp;
>> +    }
>> +  else
>> +    {
>> +      /* Keep walking the expression.  */
>> +      d->is_root = false;
>> +      return NULL_TREE;
>> +    }
>>  }
>>  
>> -/* Access functions to mark sub expressions as attributed with
>> -   __preserve_access_index.
>> -   This is required since in gimple format, in order to convert an 
>> expression as
>> -   CO-RE safe, we must create multiple gimple statements.
>> -   Also, only the type of the base of the expression might be attributed 
>> with
>> -   __preserve_access_index.  Nevertheless all the consecutive accesses to 
>> this
>> -   attributed node should also be converted to CO-RE safe.
>> -   Any LHS assigned values with CO-RE converted expressions are marked and
>> -   any uses of these values are later checked for further convertion.
>> -   The core_access_index_map functions allow to mark this nodes for later
>> -   convertion to CO-RE.
>> -   This mechanism are used by make_gimple_core_safe_access_index.  */
>> -
>> -static GTY(()) hash_map<tree, tree> *core_access_index_map = NULL;
>> +/* Walk an expression and return the node at any location in the expression
>> +   where we should break the expression in its CO-RE and non CO-RE parts.  
>> */
>>  
>> -static void
>> -core_access_clean (void)
>> +static tree *
>> +find_next_split_location (tree *tp, bool is_first)
>>  {
>> -  if (core_access_index_map == NULL)
>> -    core_access_index_map = hash_map<tree, tree>::create_ggc (10);
>> -  core_access_index_map->empty ();
>> +  struct walker_data data = { is_first, NULL };
>> +  walk_tree (tp, callback_find_next_split_location, &data, NULL);
>> +  return data.core_base_pointer;
>>  }
>>  
>> -static bool
>> -core_is_access_index (tree expr)
>> +
>> +static tree
>> +callback_should_do_core_access (tree *tp,
>> +                            int *walk_subtrees ATTRIBUTE_UNUSED,
>> +                            void *data ATTRIBUTE_UNUSED)
>>  {
>> -  if (TREE_CODE (expr) == MEM_REF
>> -      || TREE_CODE (expr) == INDIRECT_REF)
>> -    expr = TREE_OPERAND (expr, 0);
>> +/* TODO NOTE: This might have to be removed later as it is an exception
>> +   to mimic clang behavior.  */
>
> What behavior?  Please elaborate a little in the comment.
>
>> +  if (lookup_attribute ("packed", TYPE_ATTRIBUTES (TREE_TYPE (*tp))) != 
>> NULL_TREE)
>> +  {
>> +    warning_at (EXPR_LOC_OR_LOC (*tp, UNKNOWN_LOCATION), OPT_Wbpf_core,
>> +      "CO-RE expression not guaranteed, struct attribute packed with "
>> +      "preserve-access-index attributed struct childs");
>
> This warning message as written doesn't make much sense to me.
>
> From what I understand (also based on discussions in IRC), the problem
> is that if we access a p-a-i struct member of a struct which is packed
> like in:
>
> struct A {
>   int x;
> } __attribute__((preserve_access_index))
>
> struct B {
>   struct A a;
> } __attribute__((packed))
>
> int foo (struct B *b)
> {
>   return b->a.x;
> }
>
> ...Then it may not be possible to always patch the instructions which
> access 'a.x' depending on how the structs change on a different kernel
> version.  Right?
>
> I suggest rewording the warning message to something like
>
>   "Access [to member x] through packed struct may not be possible
>    to patch via CO-RE"
>
> (bonus points for stuff in [] or precise location info to point to it)
>
>
>
>> +    return *tp;
>> +  }
>> +  return NULL_TREE;
>> +}
>>  
>> -  tree *def = core_access_index_map->get (expr);
>> -  if (def)
>> -    return true;
>> -  return false;
>> +
>> +static bool
>> +should_do_core_access (tree *tp)
>> +{
>> +  tree tfail = walk_tree (tp, callback_should_do_core_access, NULL, NULL);
>> +  return tfail == NULL_TREE;
>>  }
>>  
>> -static void
>> -core_mark_as_access_index (tree expr)
>> +/* This is the main callback function to the gimple traversal that will 
>> split
>> +   any field/union accesses in their CO-RE and non CO-RE parts.
>> +   An early version of this callback would allow also allow its walker 
>> function
>> +   to traverse the parent tree expression on any initial expression 
>> (children
>> +   tree node), by not setting walk_subtrees to false. In current version 
>> only
>> +   the main tree node of an expression is reached by the traversal function
>> +   that uses this callback. The sub traversal of the main tree nodes is 
>> done in
>> +   find_next_split_location call.  The function iterates on the parent
>> +   expressions within the loop that call find_next_split_location function. 
>>  */
>> +
>> +static tree
>> +gimple_core_early_split_expr (tree *tp,
>> +                          int *walk_subtrees,
>> +                          void *data)
>>  {
>> -  if (TREE_CODE (expr) == MEM_REF
>> -      || TREE_CODE (expr) == INDIRECT_REF)
>> -    expr = TREE_OPERAND (expr, 0);
>> +  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
>> +  tree *split_loc = tp;
>>  
>> -  if (core_access_index_map->get (expr) == NULL)
>> -    core_access_index_map->put (expr, NULL_TREE);
>> -}
>> +  if (!should_do_core_access (tp))
>> +    {
>> +      *walk_subtrees = false;
>> +      return NULL_TREE;
>> +    }
>> +
>> +  /* Find the next split location within expression tree.  */
>> +  tree *expr = NULL;
>> +  bool is_first = true;
>> +  while ((expr = find_next_split_location (split_loc, is_first)) != NULL)
>> +  {
>> +    gimple_seq before = NULL;
>> +
>> +    if (*expr == *split_loc && is_first == true)
>> +      break;
>> +    is_first = false;
>>  
>> -/* This function is an adaptation of make_core_safe_access_index but to be 
>> used
>> -   in gimple format trees.  It is used by execute_lower_bpf_core, when
>> -   traversing the gimple tree looking for nodes that would have its type
>> -   attributed with __preserve_access_index.  In this particular cases any of
>> -   the expressions using such attributed types must be made CO-RE safe.  */
>> +    push_gimplify_context ();
>> +    split_loc = &TREE_OPERAND (*expr, 0);
>> +
>> +    tree rhs = *expr;
>> +    bool pointer_base = false;
>> +    if (!POINTER_TYPE_P (TREE_TYPE (rhs)))
>> +      {
>> +    rhs = fold_build1 (ADDR_EXPR,
>> +                       build_pointer_type (TREE_TYPE (*expr)),
>> +                       *expr);
>> +    pointer_base = true;
>> +      }
>> +    tree lhs = create_tmp_var_raw (TREE_TYPE (rhs), "core_split");
>> +    gimple_add_tmp_var (lhs);
>> +    gimplify_assign (lhs, rhs, &before);
>> +
>> +    if (pointer_base == true)
>> +      lhs = fold_build2 (MEM_REF, TREE_TYPE (lhs), lhs,
>> +                     build_int_cst (ptr_type_node, 0));
>> +    *expr = lhs;
>> +
>> +    gsi_insert_seq_before (&(wi->gsi), before, GSI_NEW_STMT);
>> +    pop_gimplify_context (NULL);
>> +  }
>> +
>> +  /* Never traverse subtrees, as find_next_split_location already does it. 
>> */
>> +  *walk_subtrees = false;
>> +
>> +  /* Keep traverse all the other tree expressions in gimple. */
>> +  return NULL_TREE;
>
> very minor nit but I noticed it so: dot, space, space, star slash
>  for the two comments above.
>
>> +}
>>  
>>  static tree
>> -make_gimple_core_safe_access_index (tree *tp,
>> -                                int *walk_subtrees ATTRIBUTE_UNUSED,
>> -                                void *data)
>> +core_make_builtins (tree *tp, int *walk_subtrees, void *data)
>>  {
>>    struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
>> -  bool valid = true;
>>    int n = 0;
>> +  bool valid = true;
>> +  tree expr = *tp;
>> +  bool is_addr_expr = false;
>>  
>> -  tree *patch = tp;
>> -  if (TREE_CODE (*patch) == ADDR_EXPR)
>> -    patch = &(TREE_OPERAND (*tp, 0));
>> -  tree orig_type = TREE_TYPE (*patch);
>> +  if (!should_do_core_access (tp))
>> +    {
>> +      *walk_subtrees = false;
>> +      return NULL_TREE;
>> +    }
>>  
>> -  if ((is_attr_preserve_access (*patch)
>> -      || core_is_access_index (maybe_get_base_for_field_expr (*patch)))
>> -      && (n = compute_field_expr (*patch, NULL, &valid, NULL)) > 0
>> +  /* Skip ADDR_EXPR node since we will convert to pointer anyway.  */
>> +  if (TREE_CODE (*tp) == ADDR_EXPR)
>> +    {
>> +      is_addr_expr = true;
>> +      expr = TREE_OPERAND (*tp, 0);
>> +    }
>> +
>> +  if (is_attr_preserve_access (expr)
>> +      && (n = compute_field_expr (expr, NULL, &valid, NULL)) > 0
>>        && valid == true)
>>      {
>> -      bool changed = false;
>> -      tree expr_test = make_core_safe_access_index (*patch, &changed);
>> +      poly_int64 bitsize, bitpos;
>> +      tree var_off;
>> +      machine_mode mode;
>> +      int sign, reverse, vol;
>>  
>> +      tree base = get_inner_reference (expr, &bitsize, &bitpos, &var_off, 
>> &mode,
>> +                                   &sign, &reverse, &vol);
>>  
>> -      gimple_seq before = NULL;
>> -      push_gimplify_context ();
>> -      gimplify_expr (&expr_test, &before, NULL, is_gimple_val, fb_rvalue);
>> +      tree new_expr = core_expr_with_field_expr_plus_base (base, expr, 
>> true);
>>  
>> -      /* In case the ADDR_EXPR bypassed above is no longer needed.  */
>> -      if (patch != tp && TREE_TYPE (expr_test) == TREE_TYPE (*tp))
>> -    *tp = expr_test;
>> -      /* For non pointer value accesses.  */
>> -      else if (TREE_TYPE (expr_test) == build_pointer_type (orig_type))
>> -    *patch = fold_build2 (MEM_REF, TREE_TYPE (*patch),
>> -                          expr_test, build_int_cst (ptr_type_node, 0));
>> -      else
>> -    *patch = expr_test;
>> +      /* Abort convertion if it is just a pointer or a reference to an
>> +     attributed type.  */
>> +      if (new_expr != expr)
>> +    {
>>  
>> -      *tp = fold (*tp);
>> +      gimple_seq before = NULL;
>> +      push_gimplify_context ();
>>  
>> -      gsi_insert_seq_before (&(wi->gsi), before, GSI_LAST_NEW_STMT);
>> -      pop_gimplify_context (NULL);
>> +      gimplify_expr (&new_expr, &before, NULL, is_gimple_val, fb_rvalue);
>>  
>> -      wi->changed = true;
>> -      *walk_subtrees = false;
>> +      tree new_expr_type = TREE_TYPE (new_expr);
>> +
>> +      /* Replace original expression by new_expr. If the type is the same
>> +       * tree node, good! If it is a pointer type, we need to the type
>> +       * within the pointer to guarantee it is actually the same.  */
>
> nit but the block comment styling should not prepend * on every line.
>
>> +      if (TREE_TYPE (new_expr) == TREE_TYPE (*tp)
>> +          || (is_addr_expr
>> +              && TREE_TYPE (new_expr_type) == TREE_TYPE (expr)))
>> +        *tp = fold (new_expr);
>> +      else if (TREE_TYPE (new_expr) == build_pointer_type (TREE_TYPE (*tp)))
>> +        *tp = fold_build2 (MEM_REF, TREE_TYPE (*tp),
>> +                           new_expr, build_int_cst (ptr_type_node, 0));
>> +      else
>> +        gcc_assert (0);
>>  
>> -      tree lhs;
>> -      if (!wi->is_lhs
>> -      && gimple_code (wi->stmt) != GIMPLE_CALL
>> -      && (lhs = gimple_get_lhs (wi->stmt)) != NULL_TREE)
>> -    core_mark_as_access_index (lhs);
>> +      gsi_insert_seq_before (&(wi->gsi), before, GSI_SAME_STMT);
>> +      pop_gimplify_context (NULL);
>> +
>> +      *walk_subtrees = false;
>> +    }
>>      }
>>    return NULL_TREE;
>>  }
>>  
>>  /* This is the entry point for the pass_data_lower_bpg_core.  It walks all 
>> the
>>     statements in gimple, looking for expressions that are suppose to be 
>> CO-RE
>> -   preserve_access_index attributed.
>> -   Those expressions are processed and split by
>> -   make_gimple_core_safe_access_index function, which will both create the
>> -   calls to __build_core_reloc and split the expression in smaller parts in
>> -   case it cannot be represented CO-RE safeguarded by a single CO-RE
>> -   relocation.  */
>> -
>> +   preserve_access_index attributed, and should not.
>> +   It first splits CO-RE expressions from non CO-RE ones.
>> +   Then the CO-RE expressions are processed by core_make_builtins which will
>> +   create the required builtins that will result in the CO-RE relocations.  
>> */
>>  static unsigned int
>>  execute_lower_bpf_core (void)
>>  {
>> @@ -1851,13 +1960,14 @@ execute_lower_bpf_core (void)
>>    gimple_seq body = gimple_body (current_function_decl);
>>  
>>    struct walk_stmt_info wi;
>> -  core_access_clean ();
>> -
>>    memset (&wi, 0, sizeof (wi));
>> -  wi.info = NULL;
>>  
>> -  /* Split preserve_access_index expressions when needed.  */
>> -  walk_gimple_seq_mod (&body, NULL, make_gimple_core_safe_access_index, 
>> &wi);
>> +  /* Early split to guarantee base of expression is a preserve_access_index
>> +     structure.  */
>> +  walk_gimple_seq_mod (&body, NULL, gimple_core_early_split_expr, &wi);
>> +
>> +  /* Add CO-RE builtins for all expressions that need them.  */
>> +  walk_gimple_seq_mod (&body, NULL, core_make_builtins, &wi);
>>    return 0;
>>  }
>>  
>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-3.c 
>> b/gcc/testsuite/gcc.target/bpf/core-attr-3.c
>> index 12354fc6f86d..58c27fd43bb4 100644
>> --- a/gcc/testsuite/gcc.target/bpf/core-attr-3.c
>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-3.c
>> @@ -11,14 +11,14 @@
>>  struct O {
>>    int e;
>>    int f;
>> -};
>> +} __attribute__((preserve_access_index));
>>  
>>  struct S {
>>    int a;
>>    struct {
>>      int b;
>>      int c;
>> -  } inner;
>> +  } __attribute__((preserve_access_index)) inner;
>>    struct O other;
>>  } __attribute__((preserve_access_index));
>>  
>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-4.c 
>> b/gcc/testsuite/gcc.target/bpf/core-attr-4.c
>> index 6f025f42f3ee..c001b5b76ef9 100644
>> --- a/gcc/testsuite/gcc.target/bpf/core-attr-4.c
>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-4.c
>> @@ -13,8 +13,8 @@ struct T {
>>        int d;
>>        int e[4];
>>        int f;
>> -    } v;
>> -  } u;
>> +    } __attribute__((preserve_access_index)) v;
>> +  } __attribute__((preserve_access_index)) u;
>>  } __attribute__((preserve_access_index));
>>  
>>  
>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-5.c 
>> b/gcc/testsuite/gcc.target/bpf/core-attr-5.c
>> index 81e25fa85de7..4d443d88b0ae 100644
>> --- a/gcc/testsuite/gcc.target/bpf/core-attr-5.c
>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-5.c
>> @@ -11,7 +11,7 @@ struct U {
>>      int e[4];
>>      int f;
>>      int *g;
>> -  } v;
>> +  } __attribute__((preserve_access_index)) v;
>>  } __attribute__((preserve_access_index));
>>  
>>  struct T {
>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-6.c 
>> b/gcc/testsuite/gcc.target/bpf/core-attr-6.c
>> index 25215b5ae376..d43825ea97c3 100644
>> --- a/gcc/testsuite/gcc.target/bpf/core-attr-6.c
>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-6.c
>> @@ -11,8 +11,8 @@ struct U {
>>      int e[4];
>>      int f;
>>      int *g;
>> -  } v;
>> -} u;
>> +  } __attribute__((preserve_access_index)) v;
>> +} __attribute__((preserve_access_index)) u;
>>  
>>  struct T {
>>    int a;
>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-7.c 
>> b/gcc/testsuite/gcc.target/bpf/core-attr-7.c
>> new file mode 100644
>> index 000000000000..342f69e379ba
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-7.c
>> @@ -0,0 +1,150 @@
>> +/* Test for BPF CO-RE __attribute__((preserve_access_index)) with accesses 
>> on
>> +   LHS and both LHS and RHS of assignment.  */
>> +
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -dA -gbtf -mco-re -masm=normal" } */
>> +
>> +struct other
>> +{
>> +  char c;
>> +  int i;
>> +};
>> +
>> +struct inner_attr1
>> +{
>> +  int i1;
>> +  int i2;
>> +} __attribute__((preserve_access_index));
>> +
>> +struct inner_noattr
>> +{
>> +  int i1;
>> +  int i2;
>> +};
>> +
>> +union A_noattr
>> +{
>> +  struct inner_attr1 inner_attr;
>> +  struct inner_noattr inner_no_attr;
>> +  struct inner_noattr *inner_p;
>> +};
>> +union A_attr
>> +{
>> +  struct inner_attr1 inner_attr;
>> +  struct inner_noattr inner_no_attr;
>> +  struct inner_noattr *inner_p;
>> +} __attribute__((preserve_access_index));
>> +
>> +
>> +struct outer_noattr
>> +{
>> +  struct other *other;
>> +  struct inner_attr
>> +  {
>> +    int i1;
>> +    int i2;
>> +  } __attribute__((preserve_access_index)) inner;
>> +  struct inner_noattr inner_no_attr;
>> +  struct inner_attr1 *inner_p;
>> +  union A_attr a_attr;
>> +  union A_noattr a_noattr;
>> +};
>> +
>> +struct outer_attr
>> +{
>> +  struct other *other;
>> +  struct inner_attr
>> +  {
>> +    int i1;
>> +    int i2;
>> +  } __attribute__((preserve_access_index)) inner;
>> +
>> +  struct inner_noattr inner_no_attr;
>> +  struct inner_attr1 *inner_p;
>> +  union A_attr a_attr;
>> +  union A_noattr a_noattr;
>> +} __attribute__((preserve_access_index));
>> +
>> +extern void use_value(int);
>> +
>> +void
>> +func (struct outer_noattr *o, struct outer_attr *o_attr)
>> +{
>> +  /* 0:1 */
>> +  o->inner.i2 = 7;
>> +  /* 0:1 */
>> +  o->inner_p->i2 = 8;
>> +  /* nothing */
>> +  o->inner_no_attr.i2 = 9;
>> +
>> +  /* 0:2 */
>> +  o_attr->inner_no_attr.i2 = 10;
>> +
>> +  /* nothing */
>> +  o->a_noattr.inner_no_attr.i1 = 1;
>> +  /* 0:1 */
>> +  o->a_attr.inner_no_attr.i1 = 2;
>> +  /* 0:0 */
>> +  o->a_noattr.inner_attr.i1 = 3;
>> +  /* 0:4:0:0 */
>> +  o_attr->a_attr.inner_attr.i1 = 4;
>> +  /* 0:5    0:0 */
>> +  o_attr->a_noattr.inner_attr.i1 = 5;
>> +
>> +  /* This would still force everything as being attributed, although none of
>> +     the structs has the attribute.  */
>> +  /* 0:5:2  0:0 */
>> +  __builtin_preserve_access_index (({ o->a_noattr.inner_p->i1 = 20; }));
>> +
>> +  /* 0:2 */
>> +  struct inner_noattr d = o_attr->inner_no_attr;
>> +  use_value(d.i2);
>> +}
>> +
>> +
>> +extern void use(void *);
>> +
>> +struct udphdr {
>> +    int source;
>> +    int dest;
>> +    int len;
>> +    int check;
>> +} __attribute__((preserve_access_index));
>> +
>> +union l4hdr {
>> +    struct udphdr udp;
>> +    int c;
>> +};
>> +
>> +struct v4hdr {
>> +    int a;
>> +    union l4hdr l4hdr;
>> +    int b;
>> +};
>> +
>> +void gimple_loop_error(void)
>> +{
>> +  struct v4hdr h_outer;
>> +  h_outer.l4hdr.udp.source = 1024;
>> +  use(&h_outer.l4hdr.udp.source);
>> +}
>> +
>> +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t 
>> \]+\[^\n\]*btf_aux_string" 1 } } */
>> +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t 
>> \]+\[^\n\]*btf_aux_string" 1 } } */
>> +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t 
>> \]+\[^\n\]*btf_aux_string" 1 } } */
>> +/* { dg-final { scan-assembler-times "ascii \"0:5.0\"\[\t 
>> \]+\[^\n\]*btf_aux_string" 1 } } */
>> +/* { dg-final { scan-assembler-times "ascii \"0:4:0:0.0\"\[\t 
>> \]+\[^\n\]*btf_aux_string" 1 } } */
>> +/* { dg-final { scan-assembler-times "ascii \"0:5:2.0\"\[\t 
>> \]+\[^\n\]*btf_aux_string" 1 } } */
>> +
>> +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 4 } } */
>> +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1\"\\)" 3 } } */
>> +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:2\"\\)" 2 } } */
>> +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:5\"\\)" 1 } } */
>> +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:4:0:0\"\\)" 1 } 
>> } */
>> +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:5:2\"\\)" 1 } } 
>> */
>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct inner_attr\\)" 1 
>> } } */
>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct inner_attr1\\)" 
>> 3 } } */
>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct outer_attr\\)" 4 
>> } } */
>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(union A_attr\\)" 1 } } 
>> */
>> +
>> +
>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-calls.c 
>> b/gcc/testsuite/gcc.target/bpf/core-attr-calls.c
>> index 87290c5c2116..27b08af1bb79 100644
>> --- a/gcc/testsuite/gcc.target/bpf/core-attr-calls.c
>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-calls.c
>> @@ -37,13 +37,13 @@ func (struct T *t, int i)
>>    /* 0:3  */
>>    get_other_u(t->ptr_u)->c = 43;
>>  
>> -  /* 0:2:1  */
>> +  /* 0:2  */
>>    get_other_v(&t->u.v)->d = 44;
>>  }
>>  
>>  /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:3\"\\)" 2 } } */
>>  /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 1 } } */
>> -/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:2:1\"\\)" 1 } } 
>> */
>> +/* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:2\"\\)" 1 } } */
>>  /* { dg-final { scan-assembler-times "bpfcr_type \\(struct T\\)" 3 } } */
>>  /* { dg-final { scan-assembler-times "bpfcr_type \\(struct U\\)" 1 } } */
>>  

Reply via email to