【问题标题】:constant propagation after register allocation寄存器分配后的持续传播
【发布时间】:2013-02-28 17:34:24
【问题描述】:

我想知道为什么不建议在寄存器分配 (RA) 之后进行持续传播。经过几次优化(后 RA)后,就有了窥孔优化的空间,例如恒定传播/死代码消除等。 我只能想到两个原因,

  1. 这些优化很容易在 SSA 表单上进行。
  2. 窥视孔选项。 post RA 将导致编译时间增加。

还有其他原因吗?

如果可以执行窥视孔选择。发布 RA 那么数据结构/算法应该是什么(任何论文、参考资料等都会有所帮助)。

编辑: 响应 500 - Internal Server Error 的评论。 在 phi 消除(例如,在 llvm-clang 中,与寄存器分配合并)等优化通过之后,全局调度如:将指令拉到父基本块等。

EDIT2:

如图所示的例子: 寄存器分配器发现 v1 和 v2 具有相同的值,因此将相同的寄存器 (r1) 分配给它们。寄存器分配后一个公共子表达式消除 pass 可以从基本块#4中消除r2 = r1

【问题讨论】:

  • 一个更好的问题是:寄存器分配之后的持续传播在寄存器分配之前有什么好处?
  • 在以前无法轻易(可能更容易)检测到的寄存器分配之后,可以发现哪些持续传播的潜力?
  • @Mysticial,我不赞成一种方法。我想知道为什么我们没有两者(一般来说)。
  • 基本上我的意思是在寄存器分配之后执行它不太可能比以前提供更好的结果。那么,如果您以前可以一次完成所有操作,为什么还要费心呢?
  • 这不是不可能的,我已经看到了 const 的范围。支柱。在程序集中生成;这就是我一开始好奇的原因。我试图推测 w.r.t 的权衡取舍。实现,编译时间等。

标签: c++ assembly compiler-construction llvm compiler-optimization


【解决方案1】:

见:Constant folding

给出的例子,

 int x = 14;
 int y = 7 - x / 2;
 return y * (28 / x + 2);

x 在常量折叠后完全未使用。如果首先使用 RA,它将为x 创建寄存器。因此,在运行 RA 阶段之前有机会进行一些修剪,即使结果相同。如果有更多变量,则可以避免溢出。分配寄存器后这些将很难撤消。

我认为您正在考虑strength reduction,而不是不断传播?这更符合窥孔优化的精神;或者我不明白你在 peephole 阶段(通常是后端部分)中的 不断传播 是什么意思。

寄存器分配之前应用的任何常量折叠都应该是相同的,除非变量已经被设为常量或者代码被发现死了;即CFG 已更改。per Mystical

SSA Elimination after Register Allocation 描述 LLVM 结构。我相信 SSA 可以用常数值进行注释,以便在 Phi 消除 时避免不必要的移动。这可能是 在 RA 之后消除 SSA 的产物,其他编译器不会遇到此问题。单独的传递会减慢编译速度,因此在现有传递中解决问题会更好。我认为下面的代码说明了这个问题,

 int foo(int a, int b)
 {
    int c;
    if(a > 0)
        c = 7;
    else
        c = a * b + 10;
    return a + c;
 }

phi 消除后,代码看起来像,

 int foo(int a, int b)
 {
    int c;
    if(a > 0) {
        c = 7;
        return a + c;  /* Should reduce to "a+7" */
    } else {
        c = a * b + 10;
        return a + c;
    }
 }

【讨论】:

  • 我没有忽略 const。支柱。在RA之前。当会有“一个更多”的常量时,我​​试图找到一个权衡。支柱。在 RA 之后通过。
  • 我已经在我的编辑回复中回答了您的一些问题。在寄存器分配之后有一些传递,这些传递暴露了要传播的常量,以及要删除的指令。
猜你喜欢
  • 1970-01-01
  • 2019-07-30
  • 1970-01-01
  • 2015-08-11
  • 1970-01-01
  • 2021-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多