https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104475

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jason at gcc dot gnu.org

--- Comment #20 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Thiago Macieira from comment #19)
> (In reply to Richard Biener from comment #15)
> > Thanks, it's still the same reason - we isolate a nullptr case and end up
> > with
> > 
> > __atomic_or_fetch_4 (184B, 64, 0); [tail call]
> > 
> > The path we isolate is d->m_mutex == nullptr && !enable in
> > 
> > void QFutureInterfaceBase::setThrottled(bool enable)
> > {
> >     QMutexLocker lock(&d->m_mutex);
> 
> Thank you for the analysis, Richard. But do note that it's &d->m_mutex, not
> d->m_mutex that is passed to the locker. C++ says that if you do d-> then d
> != nullptr, so &d->m_mutex can't be nullptr either.

Hmm, I see

<bb 2> [local count: 1073741824]:
_1 = this_10(D)->d;
_2 = &_1->m_mutex;
MEM[(struct __as_base  &)&lock] ={v} {CLOBBER};
if (_2 != 0B)

so we load the pointer 'this_10(D)->d' and then indeed check &d->m_mutex
for being NULL.

The middle-end long allowed &nullptr->x for the sake of legacy code
implementing offsetof by pointer arithmetic on an object at NULL.

Given

struct X { int a; int b ; };
int foo (struct X *x)
{
  return &x->a != (int *)0;
}

we do indeed not simplify this.  Doing &x->b != (int *)0 shows even that
is only simplified by recent code in Ranger (via DOM at -O1 or VRP at -O2).
That's also true for the

struct X { int a; int b ; };
int foo (struct X *x)
{
  int *p = (int *)x + 1;
  return p != (int *)0;
}

variant.  Special-casing this in the language frontends probably won't
fix the testcase since the use in a nullptr comparison is hidden
via a function call of the CTOR:

    QMutexLocker lock(&d->m_mutex);

and as you say m_mutex is at offset zero.

Since consider pointer overflow undefined we should be able to optimize
&x->b != nullptr in the middle-end earlier and more consistently.  The
offset zero case is harder since we consider &x->b as just pointer
arithmetic and x + 0 != nullptr cannot be optimized I think.

Reply via email to