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