<p>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).</p>
<p>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.</p>
<p>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?</p>

<compilers><optimization><code-generation><linker>
How does link-time function inlining work?
CC BY-SA 4.0
2024-02-28T18:44:35.447Z
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?
kaya3
CC BY-SA 4.0
2024-02-28T21:33:32.463Z
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.
Borisav Živanović
CC BY-SA 4.0
2024-02-28T21:50:41.280Z
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.
kaya3
CC BY-SA 4.0
2024-02-28T22:03:58.427Z
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?
Borisav Živanović
<p><a href="https://llvm.org/docs/LinkTimeOptimization.html" rel="noreferrer">LLVM link time optimizations</a> are implemented by having the intermediate <code>.o</code> 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 <code>.o</code> files since they don't contain bitcode.</p>

CC BY-SA 4.0
2024-02-29T07:51:52.670Z
2024-02-29T07:51:52.670Z
chc4
CC BY-SA 4.0
2024-03-03T16:06:43.980Z
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.
Borisav Živanović
CC BY-SA 4.0
2024-03-13T11:35:09.300Z
@BorisavŽivanović: Indeed. GCC employs the same scheme. In effect, the compilers are actually deferring the actual lowering to assembly until link-time.
Matthieu M.
# How does link-time function inlining work?
Posted by: username_0 on 2024-02-28
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?
**Tags:** compilers optimization code-generation linker
> **Comments:**
> **username_1**: 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?  
> **username_0**: 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.  
> **username_1**: 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.  
> **username_0**: 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?  
---
## 1 answers
### Answer by username_2 on 2024-02-29. Score: 6 | Accepted answer
[LLVM link time optimizations](https://llvm.org/docs/LinkTimeOptimization.html) 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.
> **Comments:**
> **username_0** (2024-03-03): 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.  
> **username_3** (2024-03-13): @BorisavŽivanović: Indeed. GCC employs the same scheme. In effect, the compilers are actually deferring the actual lowering to assembly until link-time.  
---
