On Thu, Jul 17, 2025 at 03:26:05PM +0000, Qing Zhao wrote: > How about add a new flag to distinguish these two cases, and put it to the > 3th argument: > > ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE, > TYPE_OF_SIZE + ACCESS_MODE + IS_POINTER, TYPE_SIZE_UNIT > for element) > which returns the REF_TO_OBJ same as the 1st argument; > > 1st argument REF_TO_OBJ: The reference to the object when IS_POINTER is > false; > The address of the reference > to the object when IS_POINTER is true; > 2nd argument REF_TO_SIZE: The reference to the size of the object, > 3rd argument TYPE_OF_SIZE + ACCESS_MODE + IS_POINTER An integer constant > with a pointer > TYPE. > The pointee TYPE of the pointer TYPE is the TYPE of the object referenced > by REF_TO_SIZE. > The integer constant value represents the ACCESS_MODE + IS_POINTER: > 00: none > 01: read_only > 10: write_only > 11: read_write > 100: IS_POINTER
Sure, I was talking about it before, the value of the 3rd argument can be a set of various bit flags. I still don't understand what do you want to use that read_only/write_only/read_write flags for, if you mark loads from the pointer, those will be always reads and whether something is load, store or load/store of data pointed by that pointer is something normally visible in the IL (plus you probably don't know it in the FE). So say for struct S { int s; int *p __attribute__((counted_by (s))); }; int foo (struct S *x, int y) { return x->p[y]; } I would have expected you emit something like _1 = x->p; _6 = &x->s; _5 = .ACCESS_WITH_SIZE (_1, _6, IS_POINTER, 4); _2 = (long unsigned int) y; _3 = _2 * 4; _4 = _5 + _3; D.2965 = *_4; and for x->p = whatever; no .ACCESS_WITH_SIZE. Jakub