A local: version node in a version script can change the effective symbol binding
to STB_LOCAL. The linker needs to communicate the fact to enable WPD
(otherwise LTO does not know that the !vcall_visibility metadata has
effectively changed from VCallVisibilityPublic to VCallVisibilityLinkageUnit).
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
lld/test/ELF/lto/devirt_vcall_vis_hidden.ll | ||
---|---|---|
25 ↗ | (On Diff #329140) | These hidden symbols should start out with Linkage Unit LTO visibility (CodeGenModule::GetVCallVisibilityLevel) |
lld/test/ELF/lto/devirt_vcall_vis_hidden.ll | ||
---|---|---|
25 ↗ | (On Diff #329140) | Yea, this shouldn't have !vcall_visibility. A version script could be used here to say that _ZTV1B is global but _ZTV1A is local. { global: _ZTV1B; local: *; }; |
lld/test/ELF/lto/devirt_vcall_vis_hidden.ll | ||
---|---|---|
25 ↗ | (On Diff #329140) | Well right now they are marked with public visibility, which is the same thing as not having any vcall_visibility. Since they are marked in the IR as having hidden visibility, clang presumably should have marked them with a more restricted vcall_visibility (linkage unit level). |
Well right now they are marked with public visibility, which is the same thing as not having any vcall_visibility. Since they are marked in the IR as having hidden visibility, clang presumably should have marked them with a more restricted vcall_visibility (linkage unit level).
Hmm? You first said "they are marked with public visibility" and then said "they are marked in the IR as having hidden visibility." I don't follow. A __attribute__(visibility("hidden"))) symbol gets the hidden attr.
lld/test/ELF/lto/devirt_vcall_vis_localize.ll | ||
---|---|---|
3 | So this test and description works fine, but the case I was originally inquiring about is an additional usage. This version script that you have below marks _ZTV1A as local and thus changes the versionId to STB_LOCAL. (SymbolTable::assignWildcardVersion) Your change in this diff causes r.ExportDynamic to be false thanks to the STB_LOCAL which is later propagated to llvm's LTO GlobalResolutions directly. This stops the vtable from being put in the DynamicExportSymbols set. (LTO::run at the top). This lets the vcall_visiblity metadata get applied to the vtable in updateVCallVisibilityInModule WholeProgramDevirt.cpp. And thus the devirtualization now happens even though the vtbl was not hidden to start. | |
13 | You can remove the vcall_visibility here and the --lto-whole-program-visibility combined with the version script will allow the vcall_visibility to be applied. |
An older version of the patch had the vtables marked "hidden" in the LLVM assembly. My point was that clang would have given them a non-public vcall_visibility in that case. The patch and the test case have changed though, so that now the local binding comes from the linker version script and not the input IR, which is more consistent with the case I believe you are trying to handle?
@lanza I did not know that -flto -fvisibility=hidden -fwhole-program-vtables -fvirtual-function-elimination create s`!vcall_visibility VCallVisibilityLinkageUnit`.
With VCallVisibilityLinkageUnit, WPD will be performed, no need for this change (test/ThinLTO/X86/devirt_vcall_vis_hidden.ll).
This change specifically handles localization via a local: version node in a version script, where WPD was not performed previously.
An older version of the patch had the vtables marked "hidden" in the LLVM assembly. My point was that clang would have given them a non-public vcall_visibility in that case.
Ahh, sorry, I missed that!
The patch and the test case have changed though, so that now the local binding comes from the linker version script and not the input IR, which is more consistent with the case I believe you are trying to handle?
Correct.
lld/test/ELF/lto/devirt_vcall_vis_localize.ll | ||
---|---|---|
13 | !vcall_visibility is here to better reflect the clang codegen. |
So this test and description works fine, but the case I was originally inquiring about is an additional usage.
This version script that you have below marks _ZTV1A as local and thus changes the versionId to STB_LOCAL. (SymbolTable::assignWildcardVersion)
Your change in this diff causes r.ExportDynamic to be false thanks to the STB_LOCAL which is later propagated to llvm's LTO GlobalResolutions directly.
This stops the vtable from being put in the DynamicExportSymbols set. (LTO::run at the top).
This lets the vcall_visiblity metadata get applied to the vtable in updateVCallVisibilityInModule WholeProgramDevirt.cpp. And thus the devirtualization now happens even though the vtbl was not hidden to start.