> On Thu, Aug 07, 2025 at 03:25:45PM +0000, Thomas de Bock wrote:
> > "I see what you mean, I think there is probably no way to apply the
> > optimization to all functions then indeed, since there is no way to
> > know if the early break on inequality of a field was arbitrary
> > or because it indicates the following data will be out of range.
> > My main goal currently though is applying the optimization to
> > the default comparison operator, and is it not undefined
> > behaviour to call it on an incomplete struct?
> >
> > For -O2:
> > bool __attribute__((noinline))
> > f(std::array<int32_t, 4>* x, std::array<int32_t, 4>* y) {
> >     return *x == *y;
> > }
> >
> > int main() {
> >
> >   std::array<int32_t, 4>* a;
> >   std::array<int32_t, 4>* b;
> >   a = (std::array<int32_t, 4>*)malloc(sizeof(std::array<int32_t, 3>));
> >   b = (std::array<int32_t, 4>*)malloc(sizeof(std::array<int32_t, 3>));
> >   return f(a, b);

> This has both arrays uninitialized, so it is obviously invalid.
> What I'm worried about is when they are initialized and are guaranteed
> to differ in the first allocated part.

I was mostly trying to illustrate an example of similar behaviour of
defaulted == as what I am trying to do, but I was unable to achieve
vectorization that goes out of bounds with initialized arguments,
so fair enough, bad example.

> One case is when all the members are part of the same struct, another
> is when you have multiple structs.
> struct A { char a, b, c, d; };
> struct B { struct A e; char f, g, h, i; };
> bool foo (struct A *p, struct A *q)
> {
>   if (p->a != q->a) return false;
>   if (p->b != q->b) return false;
>   if (p->c != q->c) return false;
>   if (p->d != q->d) return false;
>   struct B *r = (struct B *) p;
>   struct B *s = (struct B *) q;
>   if (r->f != s->f) return false;
>   if (r->g != s->g) return false;
>   if (r->h != s->h) return false;
>   if (r->i != s->i) return false;
>   return true;
> }
> From the IL all the loads are still from the same base in ascending
> order, but I think it must be just fine to call this with only A allocated
> if they differ in the first 4 elements, so optimizing this say into
> 64-bit loads is only ok if the pointers are guaranteed to be 64-bit aligned.

>         Jakub

I agree that the optimization pass should not interfere with this example.
I'm not doubtful that removing early breaks and adding vectorizing to all
sequences of comparisons would be a big problem.
To make sure it's not applied in this case I believe LLVM uses:
  if (!isDereferenceablePointer(Addr, LoadI->getType(), DL)) {
    LLVM_DEBUG(dbgs() << "not dereferenceable\n");
    // We need to make sure that we can do comparison in any order, so we
    // require memory to be unconditionally dereferenceable.
    return {};
  }

I agree it is likely fine to call `foo` in the example with only A allocated,
however, I am mainly interested in applying it to the default == operator,
and I do believe (but am not certain) that it is UB to pass an incomplete
object to the defaulted equality function, allowing for the optimization.
For example, I would assume that:

struct A {
  char a, b, c, d;
  bool operator==(const A&) const = default;
};
struct B {
  struct A e; char f, g, h, i;
  bool operator==(const B&) const = default;
};
bool __attribute__((noinline)) f(B* a, B* b) {
  return *a == *b;
}
int main() {
  A a;
  A b;
  a.a=0;
  b.a=1;
  return f((B*)&a, (B*)&b);
}

is undefined behaviour, even if (in the current implementation of operator==)
it nevers read out of bounds.



________________________________
From: Jakub Jelinek <ja...@redhat.com>
Sent: 07 August 2025 18:32:11
To: Thomas de Bock
Cc: Richard Biener; gcc@gcc.gnu.org
Subject: [ext] Re: Help with comparison-merging optimization pass

On Thu, Aug 07, 2025 at 03:25:45PM +0000, Thomas de Bock wrote:
> "I see what you mean, I think there is probably no way to apply the
> optimization to all functions then indeed, since there is no way to
> know if the early break on inequality of a field was arbitrary
> or because it indicates the following data will be out of range.
> My main goal currently though is applying the optimization to
> the default comparison operator, and is it not undefined
> behaviour to call it on an incomplete struct?
>
> For -O2:
> bool __attribute__((noinline))
> f(std::array<int32_t, 4>* x, std::array<int32_t, 4>* y) {
>     return *x == *y;
> }
>
> int main() {
>
>   std::array<int32_t, 4>* a;
>   std::array<int32_t, 4>* b;
>   a = (std::array<int32_t, 4>*)malloc(sizeof(std::array<int32_t, 3>));
>   b = (std::array<int32_t, 4>*)malloc(sizeof(std::array<int32_t, 3>));
>   return f(a, b);

This has both arrays uninitialized, so it is obviously invalid.
What I'm worried about is when they are initialized and are guaranteed
to differ in the first allocated part.

One case is when all the members are part of the same struct, another
is when you have multiple structs.
struct A { char a, b, c, d; };
struct B { struct A e; char f, g, h, i; };
bool foo (struct A *p, struct A *q)
{
  if (p->a != q->a) return false;
  if (p->b != q->b) return false;
  if (p->c != q->c) return false;
  if (p->d != q->d) return false;
  struct B *r = (struct B *) p;
  struct B *s = (struct B *) q;
  if (r->f != s->f) return false;
  if (r->g != s->g) return false;
  if (r->h != s->h) return false;
  if (r->i != s->i) return false;
  return true;
}
>From the IL all the loads are still from the same base in ascending
order, but I think it must be just fine to call this with only A allocated
if they differ in the first 4 elements, so optimizing this say into
64-bit loads is only ok if the pointers are guaranteed to be 64-bit aligned.

        Jakub


This e-mail and any attachments may contain information that is confidential 
and proprietary and otherwise protected from disclosure. If you are not the 
intended recipient of this e-mail, do not read, duplicate or redistribute it by 
any means. Please immediately delete it and any attachments and notify the 
sender that you have received it by mistake. Unintended recipients are 
prohibited from taking action on the basis of information in this e-mail or any 
attachments. The DRW Companies make no representations that this e-mail or any 
attachments are free of computer viruses or other defects.

Reply via email to