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.