Compiler construction 如何识别用于自动函数提取的类似表达式?

Compiler construction 如何识别用于自动函数提取的类似表达式?,compiler-construction,inline,compiler-optimization,Compiler Construction,Inline,Compiler Optimization,如何识别AST的结构公共子树,以便将它们分解为单独的函数 e、 g.给定此伪代码(假设该语言只允许纯终止函数): f(a,b,c){ 返回(a+b)*c*6; } g(x[4],k){ 变量y[4]; 对于(0..3中的i) y[i]=f(x[i],1,k); 返回y; } 不同的arr[4]; 结果=g(arr,1); …在完全专门化和内联之后,我们将得到以下表示程序结果值的基本操作树: (make-vec4 (*(arr 0)6) (*(+(arr 1)1)6) (*(+(arr 2)1)

如何识别AST的结构公共子树,以便将它们分解为单独的函数

e、 g.给定此伪代码(假设该语言只允许纯终止函数):

f(a,b,c){
返回(a+b)*c*6;
}
g(x[4],k){
变量y[4];
对于(0..3中的i)
y[i]=f(x[i],1,k);
返回y;
}
不同的arr[4];
结果=g(arr,1);
…在完全专门化和内联之后,我们将得到以下表示程序结果值的基本操作树:

(make-vec4
(*(arr 0)6)
(*(+(arr 1)1)6)
(*(+(arr 2)1)6)
(*(+(arr 3)1)6))
(这是一个可怕的例子,因为扩展的结果在结构上仍然与输入非常相似……但假设更改可以跨输入代码的结构边界传播)

人眼很明显,结果树包含三个类似的表达式,我们现在可以将它们重构为对函数的调用,比如
fn(i){return 6*(arr[i]+1)}
,因为指令缓存大小会咕哝咕哝等(或者更现实地利用
map
fold
原语)。但是编译器如何识别它们是相似的,以便将它们视为提取的候选? 消除相同的子表达式应该很容易,使用类似于哈希的方法。但是你不能用它来解决这个问题,因为从叶子向上移动所构建的散列不会以任何方式相互关联。是否有一种方法可以从根节点“向下构建”并确定两个表达式树之间的分歧点,以查看分支在何处成为参数?(没有使用任何关于原始程序形式的知识,假设原始程序已经扩展到所有人都无法识别的程度,并且无论如何可能没有得到最佳分割)


感觉应该有办法通过对子树排序和比较邻居来做到这一点,但这需要某种元素位置无关的排序…?

您想要做的就是“克隆检测”。您特别想要做的是检测抽象语法树上的克隆

这篇技术论文(由我撰写)是(上次我看的)关于如何做到这一点的最有参考价值的论文:

有一种基于这种方法的商业工具叫做CloneDR