消除特定递归调用的编译器优化技术及相关问题咨询
递归调用内联优化的编译相关问题
我写了两个简易算术表达式求值器:一个是直接匹配枚举分支计算的eval_fast,另一个是通过递归调用复用求和逻辑的eval_slow(这个示例里递归其实没必要,只是用来做测试)。
按道理,足够智能的编译器应该能识别eval_slow(Sum(...))这个递归调用不会引发新的递归——因为传入的是Sum类型,只会触发求和分支直接返回结果,不会再进入递归。所以理论上编译器可以安全内联这个递归调用,最终让eval_slow编译出和eval_fast完全相同的汇编代码。但实际测试下来,rustc目前并没有实现这个优化,eval_slow的汇编里依然保留了递归调用。
我有三个核心问题:
- 是否有编译器(不限编程语言)能实现这类优化?
- 这类优化在编译领域的文献里有没有特定名称?
- 这类优化未来能否被正确实现,还是说它的通用版本属于极难解决的开放问题?
pub enum Expr { Lit(isize), Sum(isize, isize), Sub(isize, isize), } // 直接分支匹配,高效实现 pub fn eval_fast(expr: Expr) -> isize { use Expr::*; match expr { Lit(x) => x, Sum(x, y) => x + y, Sub(x, y) => x - y } } // 期望编译器能内联这里的递归调用,但目前并未实现 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)) } }
注:此问题不局限于Rust,也标记为C++相关,因为这类优化可能存在于LLVM的语言无关编译阶段。
额外补充:这里寻求的不是尾调用优化(TCO)——上述逻辑不依赖递归调用处于尾位置。另外,和部分初始观点相反,Clang也无法在通用场景下解决这个问题:修改后的示例中递归调用不在尾位置,依然没有被内联。
内容的提问来源于stack exchange,提问作者ajp
相关产品推荐
相关产品推荐

