New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do not allocate vtable slots to consteval
functions
#83
Conversation
Also clarify that deleted functions do get assigned vtable slots (even though they don't need them), and consolidate three different places and ways in which we enumerate the same set of rules for which functions get vtable slots and when a return type adjustment is necessary, so that we only need to say "non-consteval" in one place. Fixes itanium-cxx-abi#82
No further comment after a month; accepting. |
I note that clang trunk crashes on this testcase because it still allocates a slot to f(). Avoiding the slot allocation seems like a lot of complication for a feature of minimal utility; what if we allocate a slot normally and just leave it null or pointing to something like __cxa_pure_virtual if we actually write out the vtable? ` struct B: A consteval int f() static_assert (f() == 2); B b; |
For the Itanium C++ ABI, this implements the rule added in itanium-cxx-abi/cxx-abi#83 For the MS C++ ABI, this implements the direction that seemed most plausible based on personal correspondence with MSVC developers, but is subject to change as they decide their ABI rule.
I think it's fine to revisit this decision since it looks like nobody has adopted it until recently. @zygoloid, thoughts? I personally agree with the committed design here: |
It seems wasteful to me to allocate a vtable slot that we're never going to use. The other case where we do that (for That said, I agree with @jicama that this feature is unlikely to ever be widely used and the costs listed above should be considered largely theoretical (and also not fully applicable to this case), so it's probably not worth exchanging a large amount of implementation complexity for it. I went ahead and implemented this in Clang (for both Itanium and, after discussion with some MS folks, the MS ABI), and it was largely straightforward for us, so I suppose the question is just how much implementation complexity we're talking about here. I could imagine this being a bit annoying to support for an implementation whose constant evaluation model works on a lowered representation that operates in terms of vtable accesses; is that the concern? One other thought: do we consider changing a function from being |
On Sun, Jul 5, 2020 at 3:19 PM Richard Smith ***@***.***> wrote:
It seems wasteful to me to allocate a vtable slot that we're never going
to use. The other case where we do that (for =delete virtual functions)
is a feature that I understand to be explicitly intended to support
reserving vtable slots for ABI-compatible extension / retraction of virtual
functions, but that's not the case here. The binary size cost of vtables is
measurable and important for some applications (particularly the cost of
relocations and symbol table entries). Also, the purpose of consteval is
to state "code must not be generated for this", and extending that to
vtables doesn't seem entirely unreasonable.
That said, I agree with @jicama <https://github.com/jicama> that this
feature is unlikely to ever be widely used and the costs listed above
should be considered largely theoretical (and also not fully applicable to
this case), so it's probably not worth exchanging a large amount of
implementation complexity for it. I went ahead and implemented this in
Clang (for both Itanium and, after discussion with some MS folks, the MS
ABI), and it was largely straightforward for us, so I suppose the question
is just how much implementation complexity we're talking about here. I
could imagine this being a bit annoying to support for an implementation
whose constant evaluation model works on a lowered representation that
operates in terms of vtable accesses; is that the concern?
Yes, that's how our virtual constexpr implementation works currently; to
avoid the vtable slot we'll need to reimplement virtual function lookup in
the constexpr evaluator. Which is certainly doable, it just isn't clear to
me that it's worthwhile.
One other thought: do we consider changing a function from being virtual
consteval to being virtual constexpr to be a plausible change, that we
would want to permit as an ABI-compatible change if made simultaneously for
the declaration and all overriders -- in much the same way that changing
from virtual =delete to virtual-but-not-deleted can be done as an
ABI-compatible change? If so, I think that would argue strongly in favor of
reserving a vtable slot, and adding a __cxa_consteval_virtual entry point
for such a slot to optionally invoke. I don't think this seems worth
supporting, but perhaps there are use cases for virtual consteval that
would motivate this kind of flexibility?
I'm just not sure what the use cases for virtual consteval are at all. For
cases where the objects are created and destroyed as part of constant
evaluation, no vtable is needed, so it doesn't matter whether there's a
slot, and constexpr would do just as well.
Jason
|
On Jul 5, 2020, at 3:19 PM, Richard Smith ***@***.***> wrote:
It seems wasteful to me to allocate a vtable slot that we're never going to use. The other case where we do that (for =delete virtual functions) is a feature that I understand to be explicitly intended to support reserving vtable slots for ABI-compatible extension / retraction of virtual functions, but that's not the case here. The binary size cost of vtables is measurable and important for some applications (particularly the cost of relocations and symbol table entries). Also, the purpose of consteval is to state "code must not be generated for this", and extending that to vtables doesn't seem entirely unreasonable.
Agreed. Especially since it’s not always easy to avoid emitting virtual functions even when they’re not used.
That said, I agree with @jicama <https://github.com/jicama> that this feature is unlikely to ever be widely used and the costs listed above should be considered largely theoretical (and also not fully applicable to this case), so it's probably not worth exchanging a large amount of implementation complexity for it. I went ahead and implemented this in Clang (for both Itanium and, after discussion with some MS folks, the MS ABI), and it was largely straightforward for us, so I suppose the question is just how much implementation complexity we're talking about here.
FWIW, our (EDG’s) constexpr virtual dispatch doesn’t use the data from code-gen (or even a lowered representation) at all. So no significant extra work was needed for consteval.
Daveed
|
OK, sounds like I'm in the minority here, I'll fix my compiler. Thanks.
|
For the Itanium C++ ABI, this implements the rule added in itanium-cxx-abi/cxx-abi#83 For the MS C++ ABI, this implements the direction that seemed most plausible based on personal correspondence with MSVC developers, but is subject to change as they decide their ABI rule.
For the Itanium C++ ABI, this implements the rule added in itanium-cxx-abi/cxx-abi#83 For the MS C++ ABI, this implements the direction that seemed most plausible based on personal correspondence with MSVC developers, but is subject to change as they decide their ABI rule.
Also clarify that deleted functions do get assigned vtable slots (even though they don't need them), and consolidate three different places and ways in which we enumerate the same set of rules for which functions get vtable slots and when a return type adjustment is necessary, so that we only need to say "non-consteval" in one place.
In passing, fix missing description of where and how to allocate vtable slots to implicit assignment operators (which might override a virtual assignment operator declared in a base class).
Fixes #82