>> Jose E. Marchesi writes:
>>
>>>> This patch corrects bugs within the CO-RE builtin field expression
>>>> related builtins.
>>>> The following bugs were identified and corrected based on the expected
>>>> results of bpf-next selftests testsuite.
>>>> It addresses the following problems:
>>>>  - Expressions with pointer dereferencing now point to the BTF structure
>>>>    type, instead of the structure pointer type.
>>>>  - Pointer addition to structure root is now identified and constructed
>>>>    in CO-RE relocations as if it is an array access. For example,
>>>>   "&(s+2)->b" generates "2:1" as an access string where "2" is
>>>>   refering to the access for "s+2".
>>>>
>>>> gcc/ChangeLog:
>>>>    * config/bpf/core-builtins.cc (core_field_info): Add
>>>>    support for POINTER_PLUS_EXPR in the root of the field expression.
>>>>    (bpf_core_get_index): Likewise.
>>>>    (pack_field_expr): Make the BTF type to point to the structure
>>>>    related node, instead of its pointer type.
>>>>    (make_core_safe_access_index): Correct to new code.
>>>>
>>>> gcc/testsuite/ChangeLog:
>>>>    * gcc.target/bpf/core-attr-5.c: Correct.
>>>>    * gcc.target/bpf/core-attr-6.c: Likewise.
>>>>    * gcc.target/bpf/core-attr-struct-as-array.c: Add test case for
>>>>    pointer arithmetics as array access use case.
>>>> ---
>>>>  gcc/config/bpf/core-builtins.cc               | 54 +++++++++++++++----
>>>>  gcc/testsuite/gcc.target/bpf/core-attr-5.c    |  4 +-
>>>>  gcc/testsuite/gcc.target/bpf/core-attr-6.c    |  4 +-
>>>>  .../bpf/core-attr-struct-as-array.c           | 35 ++++++++++++
>>>>  4 files changed, 82 insertions(+), 15 deletions(-)
>>>>  create mode 100644 
>>>> gcc/testsuite/gcc.target/bpf/core-attr-struct-as-array.c
>>>>
>>>> diff --git a/gcc/config/bpf/core-builtins.cc 
>>>> b/gcc/config/bpf/core-builtins.cc
>>>> index 8d8c54c1fb3d..4256fea15e49 100644
>>>> --- a/gcc/config/bpf/core-builtins.cc
>>>> +++ b/gcc/config/bpf/core-builtins.cc
>>>> @@ -388,8 +388,8 @@ core_field_info (tree src, enum btf_core_reloc_kind 
>>>> kind)
>>>>
>>>>    src = root_for_core_field_info (src);
>>>>
>>>> -  get_inner_reference (src, &bitsize, &bitpos, &var_off, &mode, 
>>>> &unsignedp,
>>>> -                 &reversep, &volatilep);
>>>> +  tree root = get_inner_reference (src, &bitsize, &bitpos, &var_off, 
>>>> &mode,
>>>> +                             &unsignedp, &reversep, &volatilep);
>>>>
>>>>    /* Note: Use DECL_BIT_FIELD_TYPE rather than DECL_BIT_FIELD here, 
>>>> because it
>>>>       remembers whether the field in question was originally declared as a
>>>> @@ -414,6 +414,23 @@ core_field_info (tree src, enum btf_core_reloc_kind 
>>>> kind)
>>>>      {
>>>>      case BPF_RELO_FIELD_BYTE_OFFSET:
>>>>        {
>>>> +  result = 0;
>>>> +  if (var_off == NULL_TREE
>>>> +      && TREE_CODE (root) == INDIRECT_REF
>>>> +      && TREE_CODE (TREE_OPERAND (root, 0)) == POINTER_PLUS_EXPR)
>>>> +    {
>>>> +      tree node = TREE_OPERAND (root, 0);
>>>> +      tree offset = TREE_OPERAND (node, 1);
>>>> +      tree type = TREE_TYPE (TREE_OPERAND (node, 0));
>>>> +      type = TREE_TYPE (type);
>>>> +
>>>> +      gcc_assert (TREE_CODE (offset) == INTEGER_CST && tree_fits_shwi_p 
>>>> (offset)
>>>> +          && COMPLETE_TYPE_P (type) && tree_fits_shwi_p (TYPE_SIZE 
>>>> (type)));
>>>
>>> What if an expression with a non-constant offset (something like s+foo)
>>> is passed to the builtin?  Wouldn't it be better to error there instead
>>> of ICEing?
>>>
>> In that case, var_off == NULL_TREE, and it did not reach the assert.
>> In any case, please notice that this code was copied from some different
>> code in the same file which in that case would actually produce the
>> error earlier.  The assert is there as a safe guard just in case the
>> other function stops detecting this case.
>>
>> In core-builtins.cc:572
>>
>>     else if (code == POINTER_PLUS_EXPR)
>>       {
>>         tree offset = TREE_OPERAND (node, 1);
>>         tree type = TREE_TYPE (TREE_OPERAND (node, 0));
>>         type = TREE_TYPE (type);
>>
>>         if (TREE_CODE (offset) == INTEGER_CST && tree_fits_shwi_p (offset)
>>             && COMPLETE_TYPE_P (type) && tree_fits_shwi_p (TYPE_SIZE (type)))
>>           {
>>             HOST_WIDE_INT offset_i = tree_to_shwi (offset);
>>             HOST_WIDE_INT type_size_i = tree_to_shwi (TYPE_SIZE_UNIT (type));
>>             if ((offset_i % type_size_i) == 0)
>>               return offset_i / type_size_i;
>>           }
>>       }
>>
>>     if (valid != NULL)
>>       *valid = false;
>>     return -1;
>>   }
>>
>> Because the code, although similar, is actually having different
>> purposes, I decided not to abstract this in an independent function. My
>> perception was that it would be more confusing.
>>
>> Without wanting to paste too much code, please notice that the function
>> with the assert is only called if the above function, does not return
>> with error (i.e. valid != false).
>
> Ok understood.
> Please submit upstream.
> Thanks!

Heh this is already upstream, sorry.
The patch is OK.
Thanks!

>
>>
>>>
>>>> +
>>>> +      HOST_WIDE_INT offset_i = tree_to_shwi (offset);
>>>> +      result += offset_i;
>>>> +    }
>>>> +
>>>>    type = unsigned_type_node;
>>>>    if (var_off != NULL_TREE)
>>>>      {
>>>> @@ -422,9 +439,9 @@ core_field_info (tree src, enum btf_core_reloc_kind 
>>>> kind)
>>>>      }
>>>>
>>>>    if (bitfieldp)
>>>> -    result = start_bitpos / 8;
>>>> +    result += start_bitpos / 8;
>>>>    else
>>>> -    result = bitpos / 8;
>>>> +    result += bitpos / 8;
>>>>        }
>>>>        break;
>>>>
>>>> @@ -552,6 +569,7 @@ bpf_core_get_index (const tree node, bool *valid)
>>>>      {
>>>>        tree offset = TREE_OPERAND (node, 1);
>>>>        tree type = TREE_TYPE (TREE_OPERAND (node, 0));
>>>> +      type = TREE_TYPE (type);
>>>>
>>>>        if (TREE_CODE (offset) == INTEGER_CST && tree_fits_shwi_p (offset)
>>>>      && COMPLETE_TYPE_P (type) && tree_fits_shwi_p (TYPE_SIZE (type)))
>>>> @@ -627,14 +645,18 @@ compute_field_expr (tree node, unsigned int 
>>>> *accessors,
>>>>
>>>>    switch (TREE_CODE (node))
>>>>      {
>>>> -    case ADDR_EXPR:
>>>> -      return 0;
>>>>      case INDIRECT_REF:
>>>> -      accessors[0] = 0;
>>>> -      return 1;
>>>> -    case POINTER_PLUS_EXPR:
>>>> -      accessors[0] = bpf_core_get_index (node, valid);
>>>> -      return 1;
>>>> +      if (TREE_CODE (node = TREE_OPERAND (node, 0)) == POINTER_PLUS_EXPR)
>>>> +  {
>>>> +    accessors[0] = bpf_core_get_index (node, valid);
>>>> +    *access_node = TREE_OPERAND (node, 0);
>>>> +    return 1;
>>>> +  }
>>>> +      else
>>>> +  {
>>>> +    accessors[0] = 0;
>>>> +    return 1;
>>>> +  }
>>>>      case COMPONENT_REF:
>>>>        n = compute_field_expr (TREE_OPERAND (node, 0), accessors,
>>>>                          valid,
>>>> @@ -660,6 +682,7 @@ compute_field_expr (tree node, unsigned int *accessors,
>>>>                          access_node, false);
>>>>        return n;
>>>>
>>>> +    case ADDR_EXPR:
>>>>      case CALL_EXPR:
>>>>      case SSA_NAME:
>>>>      case VAR_DECL:
>>>> @@ -688,6 +711,9 @@ pack_field_expr (tree *args,
>>>>    tree access_node = NULL_TREE;
>>>>    tree type = NULL_TREE;
>>>>
>>>> +  if (TREE_CODE (root) == ADDR_EXPR)
>>>> +    root = TREE_OPERAND (root, 0);
>>>> +
>>>>    ret.reloc_decision = REPLACE_CREATE_RELOCATION;
>>>>
>>>>    unsigned int accessors[100];
>>>> @@ -695,6 +721,8 @@ pack_field_expr (tree *args,
>>>>    compute_field_expr (root, accessors, &valid, &access_node, false);
>>>>
>>>>    type = TREE_TYPE (access_node);
>>>> +  if (POINTER_TYPE_P (type))
>>>> +    type = TREE_TYPE (type);
>>>>
>>>>    if (valid == true)
>>>>      {
>>>> @@ -1351,6 +1379,8 @@ make_core_safe_access_index (tree expr, bool 
>>>> *changed, bool entry = true)
>>>>    if (base == NULL_TREE || base == expr)
>>>>      return expr;
>>>>
>>>> +  base = expr;
>>>> +
>>>>    tree ret = NULL_TREE;
>>>>    int n;
>>>>    bool valid = true;
>>>> @@ -1365,6 +1395,8 @@ make_core_safe_access_index (tree expr, bool 
>>>> *changed, bool entry = true)
>>>>      {
>>>>        if (TREE_CODE (access_node) == INDIRECT_REF)
>>>>    base = TREE_OPERAND (access_node, 0);
>>>> +      else
>>>> +  base = access_node;
>>>>
>>>>        bool local_changed = false;
>>>>        ret = make_core_safe_access_index (base, &local_changed, false);
>>>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-5.c 
>>>> b/gcc/testsuite/gcc.target/bpf/core-attr-5.c
>>>> index e71901d0d4d1..90734dab3a29 100644
>>>> --- a/gcc/testsuite/gcc.target/bpf/core-attr-5.c
>>>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-5.c
>>>> @@ -63,5 +63,5 @@ func (struct T *t, int i)
>>>>  /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:2\"\\)" 1 } 
>>>> } */
>>>>  /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:1:1\"\\)" 1 
>>>> } } */
>>>>  /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 1 } } 
>>>> */
>>>> -/* { dg-final { scan-assembler-times "bpfcr_type \\(struct T \\*\\)" 4 } 
>>>> } */
>>>> -/* { dg-final { scan-assembler-times "bpfcr_type \\(struct U \\*\\)" 4 { 
>>>> xfail *-*-* } } } */
>>>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct T\\)" 4 } } */
>>>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct U\\)" 4 { 
>>>> xfail *-*-* } } } */
>>>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-6.c 
>>>> b/gcc/testsuite/gcc.target/bpf/core-attr-6.c
>>>> index 34a4c367e528..d0c5371b86e0 100644
>>>> --- a/gcc/testsuite/gcc.target/bpf/core-attr-6.c
>>>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-6.c
>>>> @@ -45,6 +45,6 @@ func (struct T *t, int i)
>>>>  /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:3\"\\)" 2 } } 
>>>> */
>>>>  /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:1:2\"\\)" 1 } 
>>>> } */
>>>>  /* { dg-final { scan-assembler-times "bpfcr_astr_off \\(\"0:0\"\\)" 1 } } 
>>>> */
>>>> -/* { dg-final { scan-assembler-times "bpfcr_type \\(struct T \\*\\)" 3 } 
>>>> } */
>>>> -/* { dg-final { scan-assembler-times "bpfcr_type \\(struct U \\*\\)" 2 } 
>>>> } */
>>>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct T\\)" 3 } } */
>>>> +/* { dg-final { scan-assembler-times "bpfcr_type \\(struct U\\)" 2 } } */
>>>>
>>>> diff --git a/gcc/testsuite/gcc.target/bpf/core-attr-struct-as-array.c 
>>>> b/gcc/testsuite/gcc.target/bpf/core-attr-struct-as-array.c
>>>> new file mode 100644
>>>> index 000000000000..3f6eb9cb97f8
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.target/bpf/core-attr-struct-as-array.c
>>>> @@ -0,0 +1,35 @@
>>>> +/* Basic test for struct __attribute__((preserve_access_index))
>>>> +   for BPF CO-RE support.  */
>>>> +
>>>> +/* { dg-do compile } */
>>>> +/* { dg-options "-O0 -dA -gbtf -mco-re" } */
>>>> +
>>>> +struct S {
>>>> +  int a;
>>>> +  int b;
>>>> +  int c;
>>>> +} __attribute__((preserve_access_index));
>>>> +
>>>> +void
>>>> +func (struct S * s)
>>>> +{
>>>> +  /* This test is marked as XFAIL since for the time being the CO-RE
>>>> +     implementation is not able to disambiguate between a point 
>>>> manipulation
>>>> +     and a CO-RE access when using preserve_access_index attribute.  The
>>>> +     current implemetantion is incorrect if we consider that STRUCT S 
>>>> might
>>>> +     have different size within the kernel.
>>>> +     This example demonstrates how the implementation of 
>>>> preserve_access_index
>>>> +     as an attribute of the type is flagile.  */
>>>> +
>>>> +  /* 2:2 */
>>>> +  int *x = &((s+2)->c);
>>>> +  *x = 4;
>>>> +
>>>> +  /* 2:1 */
>>>> +  int *y = __builtin_preserve_access_index (&((s+2)->b));
>>>> +  *y = 2;
>>>> +}
>>>> +
>>>> +/* { dg-final { scan-assembler-times "ascii \"2:2.0\"\[\t 
>>>> \]+\[^\n\]*btf_aux_string" 1 { xfail *-*-* } } } */
>>>> +/* { dg-final { scan-assembler-times "ascii \"2:1.0\"\[\t 
>>>> \]+\[^\n\]*btf_aux_string" 1 } } */
>>>> +/* { dg-final { scan-assembler-times "bpfcr_type" 2 } } */

Reply via email to