如何识别自动函数提取的相似表达式?

时间:2014-11-20 17:46:51

标签: compiler-construction inline compiler-optimization

如何识别AST的结构上常见的子树,以便将它们分解为单独的函数?

e.g。给定这个伪代码(假设该语言只允许纯粹的终止函数):

f(a, b, c) {
    return (a + b) * c * 6;
}

g(x[4], k) {
    var y[4];
    for (i in 0..3)
        y[i] = f(x[i], 1, k);
    return y;
}

varying arr[4];
result = 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); }之类的函数的调用,因为指令缓存大小是嘟m的混淆等 (或者更现实地利用例如mapfold原语。但是编译器如何将它们识别为相似,以便将它们视为提取的候选者?

使用hash-consing之类的东西,消除相同的子表达式应该很容易。但是你不能用它来解决这个问题,因为从叶子向上移动构建的哈希将不会以任何方式相互关联。有没有办法从根节点“构建”并确定两个表达式树之间的分歧点,以查看分支成为参数的位置? (没有使用原始程序形式的任何知识,假设 - 已经超出所有认可,并且无论如何可能没有被最佳分割)

感觉应该通过命令子树和比较邻居来做到这一点,但这需要某种与元素位置无关的排序......?

1 个答案:

答案 0 :(得分:3)

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

这篇技术论文(由我发表)是(我上次看过)关于如何执行此操作的最多参考文章:Clone Detection Using Abstract Syntax Trees

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