在编译器中注册分配

时间:2015-05-28 17:04:58

标签: compiler-construction code-generation cpu-registers

代码生成的寄存器分配阶段中出现的寄存器或溢出代码是什么意思,编译器后端必须将变量分配给内存或寄存器?

1 个答案:

答案 0 :(得分:7)

Hardware registers是昂贵的(无论是在芯片面积和解决它们所需的指令位数量方面),因此数量通常很少。当Spilling(或更确切地说,有效范围的数量)在给定程序点的数量超过可用寄存器的数量时,会发生live variables

考虑以下示例程序在具有两个硬件寄存器的假想机器中执行。假设除寄存器分配外,编译器不执行任何优化。

a := 1   ; liveout: {a}
b := 2   ; liveout: {a,b}
c := 3   ; liveout: {a,b,c}
d := a + b + c

由于在a的定义中使用了bd,因此它们的有效范围跨越了c的定义。但由于机器只有两个寄存器,abc在定义d时都不能保存在寄存器中。其中至少有一个必须洒出。

在最简单的溢出形式中,溢出变量的所有定义都被存储替换为stack槽,并且所有用途都被替换为载荷。某些编译器还可以选择执行寄存器到寄存器溢出,这意味着该值存储到不同类的寄存器中并从其中加载。例如,在x86-64上,编译器可能会将像rax这样的通用寄存器中的值溢出到像xmm0这样的SIMD寄存器中。这有利于减少内存流量。

作为溢出的替代方法,编译器可以改为执行有效范围分割。这涉及将有效范围分解为更小的部分 - 仅在分割点插入载荷和存储 - 以便能够着色其他无法收集的干涉图。

正如您可能想象的那样,选择哪个溢出变量会对生成的代码的性能产生重大影响。任意溢出在紧密循环中使用或定义的变量可能会带来灾难性的后果。因此,一个好的编译器可能会使用某种形式的启发式方法来估算溢出每个变量的成本,然后再做出选择。