5
$\begingroup$

I am familiar with traditional linking concepts (static and dynamic linking, relocation, PIE) and with traditional compiler optimizations (such as static expression evaluation, loop unrolling and compile-time inline).

I cannot find detailed info on how function inlining can be done during linking. I understand general function call logic on machine level, but cannot grasp linker doing inline work.

Is it just plain machine code dump that preserves function prolog and epilog? Does such mechanism prevent traditional inline optimizations related to variable and register access from happening?

$\endgroup$
4
  • $\begingroup$ Welcome! Is there a particular reason you expect function inlining to work differently at link-time compared to at an earlier time? Or a particular reason you expect link-time inlining to prevent other optimisations? $\endgroup$
    – kaya3
    Feb 28 at 18:44
  • $\begingroup$ When compiler does inlining using transformations over an intermediate representation (such as AST or TAC), a wider set of code optimizations can be performed over multiple passes. For example, having full RDA info and use/def chains can enable dead code elimination for a particular inlining instance (and thus turn callee into something similar to a macro). Without such context, by thinking wishfully, I suspect that linker can only dump callee instructions and eliminate jump/call instruction, thus eliminating the possibility of applying inter-procedural optimizaitons. $\endgroup$ Feb 28 at 21:33
  • $\begingroup$ Dead code elimination can be performed on assembly language or machine code without needing an earlier intermediate representation. The information needed for this (i.e. a control-flow graph) is easy to recover from the compiled output. Other optimisations are also possible without an AST or IR, particularly peephole optimisations which might become possible after inlining (e.g. f(x+1) where the first thing f does with its argument is subtract 1). More advanced optimisations might still be done by partially "decompiling" the linked code, i.e. building an IR from it. $\endgroup$
    – kaya3
    Feb 28 at 21:50
  • 1
    $\begingroup$ Thank you very much! Now it makes more sense. Can you please link me some proper (i.e. user friendly and not picky about friends) articles/docs for link-time inlining implementation? $\endgroup$ Feb 28 at 22:03

1 Answer 1

6
$\begingroup$

LLVM link time optimizations are implemented by having the intermediate .o files keep the bitcode for each function around instead of fully emitting unrelocated binary artifacts, so that the link step can inline those functions across code units and emit the final executable all at once. It doesn't look at the assembly for compiled functions, and e.g. can't do link time inline from non-LLVM .o files since they don't contain bitcode.

$\endgroup$
2
  • $\begingroup$ As far as I understood by reading this and GCC docs, link-time optimizations (and inlining especially) actually rely on compiler-specific IR merged from several files, and are not cross-compatible between separate compilers/linkers. So while ELF can be used to link machine code, it actually is used as a container for arbitrary compiler-specific data. $\endgroup$ Mar 3 at 16:06
  • 1
    $\begingroup$ @BorisavŽivanović: Indeed. GCC employs the same scheme. In effect, the compilers are actually deferring the actual lowering to assembly until link-time. $\endgroup$ Mar 13 at 11:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .