[PATCH 06/10] tree-object-size: Support dynamic sizes in conditions

Jakub Jelinek jakub@redhat.com
Tue Nov 23 16:17:45 GMT 2021


On Tue, Nov 23, 2021 at 09:08:35PM +0530, Siddhesh Poyarekar wrote:
> On 11/23/21 21:06, Siddhesh Poyarekar wrote:
> > On 11/23/21 20:42, Jakub Jelinek wrote:
> > > On Wed, Nov 10, 2021 at 12:31:32AM +0530, Siddhesh Poyarekar wrote:
> > > >     (object_sizes_execute): Don't insert min/max for dynamic sizes.
> > > 
> > > I'm worried about this.
> > > I'd say what we might want to do is in the early pass for __bdos
> > > compute actually __bos (i.e. the static one) and add MIN_EXPR/MAX_EXPR
> > > for the result of the __bdos call from the second pass with the
> > > statically computed value.
> > > 
> > > The reason for the MIN_EXPR/MAX_EXPR stuff is that GIMPLE optimizations
> > > can remove exact ADDR_EXPRs with detailed COMPONENT_REF etc. access paths
> > > in it, so during the late objsz2 pass the subobject modes don't work
> > > reliably anymore.  But the subobject knowledge should be the same between
> > > the static and dynamic evaluation...
> > 
> > So in the dynamic case we almost always end up with the right expression
> > in objsz1, except in cases where late optimizations make available
> > information that wasn't available earlier.  How about putting in a
> > MIN_EXPR/MAX_EXPR if we *fail* to get the subobject size instead?
> 
> Actually if we don't get a dynamic expression it's unlikely that we'll get a
> static size either, so I'm not sure if MIN_EXPR/MAX_EXPR will actually do
> anything useful.

Consider:
struct S { int a; char b[16]; int c; char d[]; };

static int
foo (struct S *s)
{
  return __builtin_object_size (&s->b[2], 1);
}

int
bar (int m)
{
  struct S *s = (struct S *) __builtin_malloc (m);
  int r = foo (s);
  __builtin_free (s);
  return r;
}

In early_objsz, foo isn't inlined, we can statically determine the maximum
bound of 14 but don't really know how large the allocation will actually be.
So, we record that foo returns MIN_EXPR <__builtin_object_size (&s->b[2], 1), 14>
and in the late objsz compute that as MIN_EXPR <-1UL, 14>.
Now, with __builtin_dynamic_object_size, I think it is pretty much the same,
you don't know how large the allocation actually is, so IMHO we want to
record MIN_EXPR <__buitin_dynamic_object_size (&s->b[2], 1), 14> and
at runtime do MIN_EXPR <m - 6, 14> or so.

It is true that it is just an upper bound, if we do:

static int
baz (struct S *s, int l)
{
  return __builtin_dynamic_object_size (l ? &s->b[3] : &s->b[2], 1);
}

int
qux (int m, int l)
{
  struct S *s = (struct S *) __builtin_malloc (m);
  int r = foo (s, l);
  __builtin_free (s);
  return r;
}

then the statically computed __bos in early_objsz would be still 14 and I
think dynamic needs to punt because it really doesn't know how large the
allocation will be.  In the late objsz it can make
m - 6 - !!l out of it for the __bdos (, 0) from it and combine that
to MIN_EXPR <m - 6 - !!l, 14> which still isn't exact, that would be
l ? MIN_EXPR <m - 7, 13> : MIN_EXPR <m - 6, 14>.
But, at late objsz time, the information that there was &s->b[3] and
&s->b[2] might be gone, consider e.g. in baz above a call
  corge ((char *) s + offsetof (struct S, b) + 2,
	 (char *) s + offsetof (struct S, b) + 3);
where SCCVN will CSE the (char *) s + offsetof (struct S, b) + 2
and &s->b[2] etc. expressions because they have the same value.
But __bos ((char *) s + offsetof (struct S, b) + 2, 1) should be
equal to __bos ((char *) s + offsetof (struct S, b) + 2, 0).

	Jakub



More information about the Gcc-patches mailing list