This is an archive of the discontinued LLVM Phabricator instance.

[WIP][clang] Add experimental option to omit the RTTI component from the vtable when -fno-rtti is used
ClosedPublic

Authored by leonardchan on Jun 7 2023, 3:48 PM.

Details

Summary

For programs that don't use RTTI, the rtti component is just replaced with a zero. This way, vtables that don't use RTTI can still cooperate with vtables that use RTTI since offset calculations on the ABI level would still work. However, if throughout your whole program you don't use RTTI at all (such as the embedded case), then this is just an unused pointer-sized component that's wasting space. This adds an experimental option for removing the RTTI component from the vtable.

Some notes:

  • This is only allowed when RTTI is disabled, so we don't have to worry about things like typeid or dynamic_cast.
  • This is a "use at your own risk" since, similar to relative vtables, everything must be compiled with this since it's an ABI breakage. That is, a program compiled with this is not guaranteed to work with a program compiled without this, even if RTTI is disabled for both programs.

Note that this is a completely different ABI flavor orthogonal to the relative-vtables ABI. That is, they can be enabled/disabled independently.

Diff Detail

Event Timeline

leonardchan created this revision.Jun 7 2023, 3:48 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 7 2023, 3:48 PM
leonardchan requested review of this revision.Jun 7 2023, 3:48 PM

It's not clear from the change description if this can be enabled orthogonally to relative-vtables. I think it should be possible to choose each switch independently, thus generating 4 variants of the vtable layout ABI.

Does any runtime code (libc++abi) ever need to know the vtable layout details when actually making use of RTTI, such that it would need to adapt to this ABI change?

It's not clear from the change description if this can be enabled orthogonally to relative-vtables. I think it should be possible to choose each switch independently, thus generating 4 variants of the vtable layout ABI.

Oh this is completely independent from relative vtables. I'll update the wording.

Does any runtime code (libc++abi) ever need to know the vtable layout details when actually making use of RTTI, such that it would need to adapt to this ABI change?

__dynamic_cast is the only thing that comes to mind, but since this is gated on -fno-rtti where dynamic_cast is disabled, then I think libc++abi doesn't need to worry about this.

leonardchan edited the summary of this revision. (Show Details)Jun 7 2023, 4:14 PM

Oh this is completely independent from relative vtables. I'll update the wording.

Great. I'd like to see us try some experiments with enabling both together in places like the Fuchsia kernel where we get benefit from relative-vtables today but it's all a single fungible internal ABI domain and there's no problem having a one-off ABI. It's also interesting of course for true embedded contexts, but those tend to be ILP32 where relative-vtables isn't a size savings anyway. In the Fuchsia kernel we should get some size savings from this and it would be nice to see what that is (probably not all that big, but interesting).

Can we extend the test cases to exercise both with and without relative-vtables also enabled?

Does any runtime code (libc++abi) ever need to know the vtable layout details when actually making use of RTTI, such that it would need to adapt to this ABI change?

__dynamic_cast is the only thing that comes to mind, but since this is gated on -fno-rtti where dynamic_cast is disabled, then I think libc++abi doesn't need to worry about this.

Perfect. This makes this a good free-floating option for any context like kernel or embedded where all code (even if libc++/libc++abi are included) are built from scratch using the same switches.

Can we extend the test cases to exercise both with and without relative-vtables also enabled?

Yup, the cases here already test with the regular itanium c++ abi and relative vtables abi.

Oh this is completely independent from relative vtables. I'll update the wording.

Great. I'd like to see us try some experiments with enabling both together in places like the Fuchsia kernel where we get benefit from relative-vtables today but it's all a single fungible internal ABI domain and there's no problem having a one-off ABI. It's also interesting of course for true embedded contexts, but those tend to be ILP32 where relative-vtables isn't a size savings anyway. In the Fuchsia kernel we should get some size savings from this and it would be nice to see what that is (probably not all that big, but interesting).

In the kernel it saves us about 664 bytes with RV. For some embedded devices I measured, savings is on the order of 1-2kB. For chromium with RV, it would save about 77076 bytes from rodata, but standalone without RV, it's twice that so 154152 bytes saved from .data.rel.ro and this would scale based on the number of processes.

phosek added inline comments.Sep 12 2023, 11:01 PM
clang/include/clang/Driver/Options.td
2249–2256

Can you use BoolFOption to simplify the definition?

2250

I think the name should signal that this is related to vtables (otherwise users might be wondering what "component" is this referring to).

We could use -fexperimental-omit-vtable-rtti-component but that's quite a mouthful, maybe -fexperimental-omit-vtable-rtti would suffice?

leonardchan marked 2 inline comments as done.
phosek accepted this revision.Sep 13 2023, 3:55 PM

LGTM

clang/include/clang/Basic/LangOptions.def
450

I'd also rename this to OmitVTableRTTI for consistency.

This revision is now accepted and ready to land.Sep 13 2023, 3:55 PM
This revision was landed with ongoing or failed builds.Sep 13 2023, 4:18 PM
This revision was automatically updated to reflect the committed changes.
leonardchan added inline comments.Sep 13 2023, 4:56 PM
clang/include/clang/Driver/Options.td
2250

I think the name should signal that this is related to vtables (otherwise users might be wondering what "component" is this referring to).

Formally, this can be used independently of relative vtables. So under the regular itanium c++ abi this would reduce the vtable by a pointer size and under RV it would reduce the vtable by an offset size. "Component" I believe is the formal name for the actual elements in the vtable: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components.

We could use -fexperimental-omit-vtable-rtti-component but that's quite a mouthful, maybe -fexperimental-omit-vtable-rtti would suffice?

WFM

dyung added a subscriber: dyung.Sep 13 2023, 9:33 PM

Hi @leonardchan your change was still causing a failure on the PS4 linux bot, so I reverted it in 070493ddbd9473499d6f00ca62bc6aa92808ed79. I noticed earlier that the failing test omit-rtti-component-without-no-rtti.cpp was failing on both the linux and Windows PS bots, and I don't think it is because it was on Windows, but rather, these bots use PS4 and PS5 as the default targets, on which rtti is not enabled by default. The run command on line 4 in your test tests the "default" behavior which on most platforms seems to have rtti enabled by default. If I remove that line, the test then passes on both of the PS targets. To reland the change, you might want to consider removing that line as it makes an assumption which does not seem to be true for all targets.

Hi @leonardchan your change was still causing a failure on the PS4 linux bot, so I reverted it in 070493ddbd9473499d6f00ca62bc6aa92808ed79. I noticed earlier that the failing test omit-rtti-component-without-no-rtti.cpp was failing on both the linux and Windows PS bots, and I don't think it is because it was on Windows, but rather, these bots use PS4 and PS5 as the default targets, on which rtti is not enabled by default. The run command on line 4 in your test tests the "default" behavior which on most platforms seems to have rtti enabled by default. If I remove that line, the test then passes on both of the PS targets. To reland the change, you might want to consider removing that line as it makes an assumption which does not seem to be true for all targets.

Ahh. Thanks for the revert and the info. I'll reland with that removed.