Inlining replaces a function call with a copy of the callee's body, wiring the arguments in directly. It removes the call/return overhead, but the real prize is what it enables: once the body is in the caller, constant propagation, CSE, and dead-code elimination can see across the old boundary and specialize the code to this call site. The cost is size (the body is duplicated at every inlined site) and a call stack that no longer matches the source — the callee has vanished into its caller.
A leaf function f(x)=x*x+1 is called, then inlined. The demo shows the value is identical and the call depth drops from 1 to 0: live demo
“Inlining just saves the cost of a call.” — the call cost is the small win; the big one is that the optimizer can now see through the call and specialize. Inlining is less about speed than about removing a wall the other passes could not look past. cited
Inlining is the enabler of enablers: it does little by itself and much by what it lets other passes reach. Its danger is the same — inline everything and the code explodes. Scheifler 1977
On the canonical compiler, f(6)=37 via a call (call depth 1) equals the inlined 6*6+1=37 (call depth 0) — same value, one less frame: