This is an archive of the discontinued LLVM Phabricator instance.

[clang] Emit type metadata on available_externally vtables for WPD
ClosedPublic

Authored by tejohnson on Feb 17 2021, 5:00 PM.

Details

Summary

When WPD is enabled, via WholeProgramVTables, emit type metadata for
available_externally vtables. Additionally, add the vtables to the
llvm.compiler.used global so that they are not prematurely eliminated
(before *LTO analysis).

This is needed to avoid devirtualizing calls to a function overriding a
class defined in a header file but with a strong definition in a shared
library. Without type metadata on the available_externally vtables from
the header, the WPD analysis never sees what a derived class is
overriding. Even if the available_externally base class functions are
pure virtual, because shared library definitions are already treated
conservatively (committed patches D91583, D96721, and D96722) we will
not devirtualize, which would be unsafe since the library might contain
overrides that aren't visible to the LTO unit.

An example is std::error_category, which is overridden in LLVM
and causing failures after a self build with WPD enabled, because
libstdc++ contains hidden overrides of the virtual base class methods.

Diff Detail

Event Timeline

tejohnson created this revision.Feb 17 2021, 5:00 PM
tejohnson requested review of this revision.Feb 17 2021, 5:00 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 17 2021, 5:00 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript

So in this case, the virtual call in user code is resolved to a strong definition in the shared library even though user code also has a derived class defined? In other words, the library provides another overrider definition as the final overrider?

So in this case, the virtual call in user code is resolved to a strong definition in the shared library even though user code also has a derived class defined? In other words, the library provides another overrider definition as the final overrider?

Yes. There is already support via LTO and the linkers to be conservative when a vtable is defined in a shared library. But without the type metadata on the available_externally vtables, LTO doesn't even know that the derived class vtable is related to the base class vtable from the shared library. So we erroneously think that there is only one possible implementation of the virtual method.

davidxl added inline comments.Feb 19 2021, 10:30 AM
clang/lib/CodeGen/ItaniumCXXABI.cpp
1770–1776

Can you add some comment here -- also help user understand the code. Note that isDeclarationForLinker is not intuitive by name.

Add comments

davidxl added inline comments.Feb 19 2021, 11:01 AM
clang/lib/CodeGen/ItaniumCXXABI.cpp
1781

Is it better to guard it with with if (CGM.getCodeGenOpts().WholeProgramVTables) which seems clearer in intention?

tejohnson added inline comments.Feb 19 2021, 11:19 AM
clang/lib/CodeGen/ItaniumCXXABI.cpp
1781

No I don't think we want to do this, it would mean every single vtable would be put on the llvm.compiler.used which is unnecessary. The available_externally are the ones that aren't sticking around otherwise.

davidxl accepted this revision.Feb 19 2021, 11:38 AM

lgtm

clang/lib/CodeGen/ItaniumCXXABI.cpp
1781

Ok. Perhaps add an assertion that wholeProgram is on in this case.

This revision is now accepted and ready to land.Feb 19 2021, 11:38 AM
This revision was landed with ongoing or failed builds.Feb 19 2021, 12:43 PM
This revision was automatically updated to reflect the committed changes.