Here are two versions of a trivial arithmetic expression evaluator (playground link: https://play.rust-lang.org/?version=nightly&mode=release&edition=2021&gist=d3da06b0077b29e0e3ac85720c567dd8)
The second version uses a recursive call to reuse some code (obviously not worth the effort in this toy example, but that's why it's a toy example).
I'm convinced that a sufficiently smart compiler could realize that the recursive call to eval_slow(Sum(...))
does not itself make any recursive calls, and therefore is safe to inline, and eval_slow
should actually compile to the same assembly as eval_fast
. In practice, rustc currently does not perform this optimization, and eval_slow
contains a recursive call (see assembly output in playground link).
Are there optimizing compilers that are capable of performing this type of optimization (for any language)? Is there a name for this type of optimization in the compiler literature? Is this likely to be optimized correctly in the near future, or is (the general version of) this a very hard open problem?
pub enum Expr {
Lit(isize),
Sum(isize, isize),
Sub(isize, isize),
}
// simple and fast
pub fn eval_fast(expr: Expr) -> isize {
use Expr::*;
match expr {
Lit(x) => x,
Sum(x, y) => x + y,
Sub(x, y) => x - y
}
}
// we'd like to inline the recursive call to `eval_slow(Sum(...))`, but it doesn't happen.
pub fn eval_slow(expr: Expr) -> isize {
use Expr::*;
match expr {
Lit(x) => x,
Sum(x, y) => x + y,
Sub(x, y) => eval_slow(Sum(x, -y))
}
}
NOTE: also tagging this as C++ since my questions aren't rust-specific, though my example is (and afaik it's quite possible that this optimization would live in the language-agnostic passes of LLVM anyway)
EDIT: TCO is not what I'm looking for - the logic above does not rely on the recursive call being in tail position. Also, contrary to some initial comments, Clang does not solve this for C++ in the general case - here's an example which has been modified such that the recursive call is not in tail position, and in which the recursive call is not inlined. https://godbolt.org/z/cGabvvvro (yes, one version prints twice - shouldn't affect main point)