Richer symbol dependency information for LTO
Description
C and C++ programs are often composed of various object files produced from separately-compiled source files that are then linked together. When compiling one source file, knowledge that can be derived from the logic contained within the other source files would normally not be available. Link-time optimization, also known as LTO, is a way for optimization to be done using information from more than one source file.
In LLVM, LTO is achieved by using LLVM bitcode objects as the output from the “compile” step and feeding those objects into the link step. LLVM’s LTO operates in conjunction with the linker. The linker is invoked by the user and the linker in turn drives LLVM’s LTO when it encounters LLVM bitcode files, getting information from LTO about what symbols a bitcode object defines or references. Information about what symbols are defined in or referenced from an object is necessary for the linker to perform symbol resolution, and a linker is normally able to extract such information from regular (non-bitcode) object files.
The implied consequences of LLVM’s LTO implementation with respect to linker GC (linker garbage collection) can be improved, especially for aggressive forms of linker GC with lazy inclusion of objects and sections. In particular, the symbols referenced but undefined by an LTO module are, to the linker, monolithic at the module level. At the same time, the symbols referenced but undefined by regular (non-LTO) objects are monolithic to LTO. Together, this means that the inclusion of an LTO module into the overall process potentially leads, in the linker’s initial symbol resolution, to all the undefined symbols in that module being considered as referenced; in turn, additional artifacts (e.g., archive members) may be added into the resolution, which further leads to references that may resolve to symbols defined in LTO modules and a premature conclusion that the definition of these symbols are needed. This at least means potentially unnecessary codegen is being done for functions that will be garbage-collected in the end (waste of electricity and time).
We acknowledge that an ideal implementation probably involves a “coroutine” like interaction between the linker and LTO codegen where information flows back and forth; however, such an endeavour is invasive to both linkers and to LLVM.
We believe that by
- having the linker register, via an API to LTO, symbol reference “nodes” modelling the relationship between a symbol and the symbols that are referenced in turn from (the object file section containing) its linker-selected definition, and
- using that information in LTO processing,
the LTO processing will be able to effectively identify a more accurate set of LTO symbols that are visible outside of the LTO unit. The linker merely needs to identify only exported symbols and entry points (such as the entry point for an executable and functions involved in the initialization and finalization).
Having the LLVM opt/codegen understand the dependency implications from the “outside world” is strictly better than the other direction: the symbols referred to by relocations in non-LTO code are pretty much fixed as compiled (whereas some references in LTO code may disappear with optimization).
Preparation resources
TBD
Expected results
- Modification of the C++ LTO interface used by LLD to implement an interface to record the symbol reference dependency data (incorporating awareness of sections and comdats). This may additionally include a method to add LTO objects provisionally, simulating behaviours where linkers only add objects as needed.
- Modification of LTO to use new symbol reference information for definitions in regular objects when visiting definitions in the IR prior to the internalization pass to discover (transitive) symbol references and record the so-referenced symbols as being visible to regular objects. This may additionally include the “late” incorporation of LTO objects added provisionally into the merged LTO module.
- Modification of LLD (for ELF) to modify initial resolution to use the new interface as a replacement for setting
VisibleToRegularObj
except for entry point functions (including C++ dynamic initialization and finalization).
Confirmed mentors
Sean Fertile, Hubert Tong, Wael Yehia
Desirable skills
Intermediate C++; basic linker concepts (e.g., symbols, sections, and relocations)
Project size
350 hours
Difficulty
Medium/Hard
@teresajohnson @Peter_Collingbourne2
cc: @Wael_Yehia1 @Sean_Fertile
Hi Teresa and Peter,
In our usage of “full” LTO, we have noticed what appear to be limitations in terms of the granularity of information accessible and communicable by the linker for symbol resolution purposes. We have been using the C API; however, it does not appear that LTO, in general, captures information about where references are made from (for example, relocations associated with a section). We have a thought about a potential Google Summer of Code project and your feedback would be appreciated. If you have other thoughts about approaching the problem, those would also be helpful.
Please see below for our draft.
Thanks,
Hubert Tong