[Bug ipa/110057] Missed devirtualization opportunities
redi at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Mon Jul 15 09:55:20 GMT 2024
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110057
--- Comment #17 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to user202729 from comment #16)
> That sound like a good idea, thanks. I thought about this some time earlier
> (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115413#c3) but I did not know
> how to check the implementation of `destroy()`.
You only need to know if Alloc::destroy exists or not.
> Nevertheless, this does not handle the case of devirtualization in vector
> access (e.g. `v[0].f()` where v is a vector and method f is virtual). What
> do you think?
I don't think that optimization would be valid. Users could do disgusting
things like this (as long as sizeof(Base) == sizeof(Derived)):
std::vector<Base> v(1);
v[0].~Base();
::new((void*)v.data()) Derived();
v[0].f();
v[0].~Derived();
::new((void*)v.data()) Base();
I'm not even 100% convinced that the destructor optimization is valid, but I
think any time there is pointer arithmetic on the vector's storage, the dynamic
types of objects in the array must match the static types. Arguably the v[0]
access above already requires that, so maybe the code above isn't valid, but I
don't think it's entirely clear from the standard.
This certainly seems to be allowed:
std::vector<Base> v(1);
Base* p = v.data();
p->~Base();
::new((void*)p) Derived();
p->f();
p->~Derived();
::new((void*)p->) Base();
If we can be sure that v[0] requires the static and dynamic types to match,
then we could do something like:
reference
operator[](size_type __n) _GLIBCXX_NOEXCEPT
{
__glibcxx_requires_subscript(__n);
#ifdef __cpp_rtti
if (typeid(this->_M_impl._M_start[__n]) != typeid(value_type))
__builtin_unreachable();
#endif
return *(this->_M_impl._M_start + __n);
}
I have no idea whether that would help anything, or if the use of typeid would
actually pessimize things.
> Apart from that, being do you think it is common for the user to override
> `destroy()` (in a template specialization) but still call the destructor
> inside it? In that case the proposal would not optimize that case.
I don't really care about that, we can't handle every case.
More information about the Gcc-bugs
mailing list