On 2025-04-07 14:53, Qing Zhao wrote:
Is there a reason to do this at the very end like this and not in the 
GIMPLE_ASSIGN case in the switch block?  Something like this:

         tree rhs = gimple_assign_rhs1 (stmt);
         tree counted_by_ref = NULL_TREE;
         if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
             || (gimple_assign_rhs_code (stmt) == ADDR_EXPR
                 && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF))
           reexamine = plus_stmt_object_size (osi, var, stmt);
         else if (gimple_assign_rhs_code (stmt) == COND_EXPR)
           reexamine = cond_expr_object_size (osi, var, stmt);
         else if (gimple_assign_single_p (stmt)
                  || gimple_assign_unary_nop_p (stmt))
           {
             if (TREE_CODE (rhs) == SSA_NAME
                 && POINTER_TYPE_P (TREE_TYPE (rhs)))
               reexamine = merge_object_sizes (osi, var, rhs);
             else
               expr_object_size (osi, var, rhs);
           }
+        else if ((counted_by_ref = fam_struct_with_counted_by (rhs)))
+          record_fam_object_size (osi, var, counted_by_ref);
         else
           unknown_object_size (osi, var);

where you can then fold in all your gating conditions, including getting the 
counted_by ref into the fam_struct_with_counted_by and then limit the 
record_fam_object_size to just evaluating the type size + counted_by size.

This may even help avoid the insertion order hack you have to do, i.e. the 
gsi_insert_seq_before vs gsi_insert_seq_after.

This is a good suggestion. I will try this to see any issue there.

My initial thought is to give the counted_by information the lowest priority
  if there are other information (for example, malloc) available.

Do you see any issue here?

No, that is the right idea, but I don't know if you'll actually need to choose. AFAICT, you'll either be able to trace the pointer to an allocation, in which case the fallback is unnecessary. Otherwise you'll trace it to one of the following:

1. An assignment from an expression that returns the pointer
2. A NOP with a var_decl, which is handled in the GIMPLE_NOP case; you'd need to add a similar hook there.

I can't think of any other cases off the top of my head, how about you?

Also, it seems like simply making build_counted_by_ref available may be 
unnecessary and maybe you could explore associating the counted_by 
component_ref with the parent type somehow.  Alternatively, how about building 
an .ACCESS_WITH_SIZE for types with FAM that have a counted_by?  That would 
allow the current access_with_size_object_size() to work out of the box.

I am not sure about this though.

Our initial design is to change every component_ref  (which is a reference to 
the FAM)
in the data flow of the routine that has a counted_by attribute to a  call to 
.ACCESS_WITH_SIZE.
Then put this call to .ACCESS_WITH_SIZE into the data flow of the routine.

Now, if we try to associate counted_by information to the parent type, how can 
we add such information
To the data flow of the routine if there is no explicit reference to the array 
itself?

I'm not entirely sure, but maybe whenever there is an access on a ptr to the parent struct, add a call to .ACCESS_WITH_SIZE there, with a built expression for its size? e.g for:

struct S
{
  size_t c;
  char a[] __counted_by (c);
}

void foo (Struct S *s)
{
  ...
  sz = __builtin_dynamic_object_size (s, 0);
  ...
}

we could generate:

void foo (struct S *s)
{
  ...
  sz_exp = c + sizeof (struct S);
  s_1 = .ACCESS_WITH_SIZE (&s..., &c, ...);
  ...
  sz = __builtin_dynamic_object_size (*s_1, 0);
}

or something like that. But like I said, it's an alternative idea to avoid special-casing in tree-object-size, which should provide size information across all passes not just for object size.

Thanks,
Sid

Reply via email to