Introduction
The LTO writer emits information required for link-time optimization in object files compiled with the -flto option. The LTO reader reads this information from object files compiled with this option.
The writer is part of the "middle end" of the compiler. Although the LTO project is focused initially on the C programming language, the writer is a language-independent component. As such, it does not rely on any data visible only to the C front end. The reader is part of the LTO front end.
Contents
Storage Formats
In broad terms, information required for link-time optimization can be divided into two categories:
- Declarations for global entities
- Function bodies
The global-entities category includes all types (including types declared within a function), function declarations (including nested functions), and global variable declarations (including all variables at file scope and local variables declared with the "static" keyword in C). The function-body category includes all executable statements and expressions.
Much of the required information about global entities (including the names of objects, their sizes, types, and so forth) is available in the debugging information the compiler generates with -g. Therefore, global entity information is encoded in the DWARF 3 format, with extensions as necessary to represent information that is not normally useful to a debugger.
Function bodies are encoded using a special-purpose format well-suite to compactly encoding GCC's TREE format. The LTO writer never writes out RTL information; function bodies are always encodings of TREE.
Global Entity Tasks
Type and Declaration Attributes
GCC's DWARF generator does not presently encode all necessary information about global entities. For example, semantic GNU attributes (e.g., __attribute__((X))) where X is something that can affect the behavior of the program, are not encoded. Other information stored in various flags associated with TREE nodes is also not encoded. Therefore:
- DWARF extensions must be specified for all such information.
- The DWARF generator must be modified to encode this information.
- The LTO reader must be modified to restore this information.
Type Information
The following are not already present in the DWARF information for types:
- Type alignment
- Machine mode
At present, the LTO reader uses layout_type to recreate certain flags on types. Instead, all necessary information should be restored from the stored DWARF information.
Declaration Information
The following are not already present in the DWARF information for variables and functions:
DECL_SECTION_NAME
DECL_VISIBILITY
DECL_ONE_ONLY
DECL_COMDAT
DECL_WEAK
DECL_DLLIMPORT_P
DECL_UNINLINABLE
DECL_IS_MALLOC
DECL_IS_RETURNS_TWICE
DECL_IS_PURE
DECL_IS_NOVOPS
DECL_STATIC_CONSTRUCTOR
DECL_STATIC_DESTRUCTOR
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT
DECL_NO_LIMIT_STACK
DECL_NO_STATIC_CHAIN
DECL_INLINE
DECL_HARD_REGISTER
DECL_HAS_INIT_PRIORITY
DECL_INIT_PRIORITY
DECL_TLS_MODEL
DECL_THREAD_LOCAL_P
DECL_IN_TEXT_SECTION
DECL_COMMON
It is not the case that we should just blindly create DWARF attributes for all of these fields. For example, the right way to represent DECL_INIT_PRIORITY is probably a DWARF attribute for that field, but the right way to represent DECL_HAS_INIT_PRIORITY is probably by the presence of absence of the DWARF attribute for DECL_INIT_PRIORITY rather than a separate bit. As another example, it may be possible to compute DECL_SECTION_NAME by looking at the ELF symbol table.
Variable Initializers
Initializers for variables with static storage duration are not represented in DWARF information because a debugger does not generally need this information. However, the information is of course present in object files. The information is represented as a combination of literal bytes (in the data section containing the variable, or, in the case of zero-initialized data, implicitly by the placement of the variable in an appropriate section) and relocations. The LTO reader must be modified to recover the initializers from data stored in object files. The reader must include processor-specific relocation processing. This processing can be provided via a back-end hook.
In order to locate variable initializers, the LTO reader will need to read the ELF symbol table. This information may also be useful in determining whether or not a function and/or variable is defined in the translation unit being read.
Symbol-Table Construction
DWARF information is a tree of nodes, beginning with a root node corresponding to an entire translation until. At present, the LTO front end makes a single depth-first pass over the DWARF tree. However, DWARF nodes may contain references to other nodes elsewhere in the tree which have not yet been encountered. Therefore, the LTO front end attempts to skip around in the tree processing nodes out of order. This approach is error-prone as parent nodes are required to provide appropriate context.
Therefore, the LTO front end should be modified to use a two-pass algorithm. The first pass will construct (incomplete) nodes for all global entities and enter them in the symbol table. The second pass will fill in the incomplete nodes. For example, on the first pass, when a DW_TAG_subprogram node is encountered:
If the function has node already been declared, a new FUNCTION_DECL node is created, and its DECL_ASSEMBLER_NAME set appropriately. Other fields remain NULL_TREE.
The child nodes of the DW_TAG_subprogram are walked.
On the second pass, when the same DW_TAG_subprogram node is encountered, all fields not already set are filled in.