Thanks a lot for raising these issues. If I understand correctly, the major question we need to answer is:
For the following example: (Jakub mentioned this in an early message) 1 struct S { int a; char b __attribute__((counted_by (a))) []; }; 2 struct S s; 3 s.a = 5; 4 char *p = &s.b[2]; 5 int i1 = __builtin_dynamic_object_size (p, 0); 6 s.a = 3; 7 int i2 = __builtin_dynamic_object_size (p, 0); Should the 2nd __bdos call (line 7) get A. the latest value of s.a (line 6) for it’s size? Or B. the value when the s.b was referenced (line 3, line 4)? A should be more convenient for the user to use the dynamic array feature. With B, the user has to modify the source code (to add code to “re-obtain” the pointer after the size was adjusted at line 6) as mentioned by Richard. This depends on how we design the new internal function .ACCESS_WITH_SIZE 1. Size is passed by value to .ACCESS_WITH_SIZE as we currently designed. PTR = .ACCESS_WITH_SIZE (PTR, SIZE, ACCESS_MODE) 2. Size is passed by reference to .ACCESS_WITH_SIZE as Jakub suggested. PTR = .ACCESS_WITH_SIZE(PTR, &SIZE, TYPEOFSIZE, ACCESS_MODE) With 1, We can only provide B, the user needs to modify the source code to get the full feature of dynamic array; With 2, We can provide A, the user will get full support to the dynamic array without restrictions in the source code. However, We have to pay additional cost for supporting A by using 2, which includes: 1. .ACCESS_WITH_SIZE will become an escape point, which will further impact the IPA optimizations, more runtime overhead. Then .ACCESS_WTH_SIZE will not be CONST, right? But it will still be PURE? 2. __builtin_dynamic_object_size will NOT be LEAF anymore. This will also impact some IPA optimizations, more runtime overhead. I think the following are the factors that make the decision: 1. How big the performance impact? 2. How important the dynamic array feature? Is adding some user restrictions as Richard mentioned feasible to support this feature? Maybe we can implement 1 first, if the full support to the dynamic array is needed, we can add 2 then? Or, we can implement both, and compare the performance difference, then decide? Qing > On Nov 2, 2023, at 8:09 AM, Jakub Jelinek <ja...@redhat.com> wrote: > > On Thu, Nov 02, 2023 at 12:52:50PM +0100, Richard Biener wrote: >>> What I meant is to emit >>> tmp_4 = .ACCESS_WITH_SIZE (&s.b[0], &s.a, (typeof (&s.a)) 0); >>> p_5 = &tmp_4[2]; >>> i.e. don't associate the pointer with a value of the size, but with >>> an address where to find the size (plus how large it is), basically escape >>> pointer to the size at that point. And __builtin_dynamic_object_size is >>> pure, >>> so supposedly it can depend on what the escaped pointer points to. >> >> Well, yeah - that would work but depend on .ACCESS_WITH_SIZE being an >> escape point (quite bad IMHO) > > That is why I've said we need to decide what cost we want to suffer because > of that. > >> and __builtin_dynamic_object_size being >> non-const (that's probably not too bad). > > It is already pure,leaf,nothrow (unlike __builtin_object_size which is > obviously > const,leaf,nothrow). Because under the hood, it can read memory when > expanded. > >>> We'd see that a particular pointer is size associated with &s.a address >>> and would use that address cast to the type of the third argument (to >>> preserve the exact pointer type on INTEGER_CST, though not sure, wouldn't >>> VN CSE it anyway if one has say >>> union U { struct S { int a; char b __attribute__((counted_by (a))) []; } s; >>> struct T { char c, d, e, f; char g __attribute__((counted_by (c))) >>> []; } t; }; >>> and >>> .ACCESS_WITH_SIZE (&v.s.b[0], &v.s.a, (int *) 0); >>> ... >>> .ACCESS_WITH_SIZE (&v.t.g[0], &v.t.c, (int *) 0); >>> ? >> >> We'd probably CSE that - the usual issue of address-with-same-value. >> >>> It would mean though that counted_by wouldn't be allowed to be a >>> bit-field... >> >> Yup. We could also pass a pointer to the container though, that's good >> enough >> for the escape, and pass the size by value in addition to that. > > I was wondering about stuff like _BitInt. But sure, counted_by is just an > extension, we can just refuse counting by _BitInt in addition to counting by > floating point, pointers, aggregates, bit-fields, or we could somehow encode > all the needed type's properties numerically into an integral constant. > Similarly for alias set (unless it uses 0 for reads). > > Jakub >