Fan*_*nts 4 compiler-construction code-generation cpu-registers
在代码生成的寄存器分配阶段中出现的寄存器或溢出代码溢出是什么意思,编译器后端必须将变量分配给存储器或寄存器?
硬件寄存器很昂贵(在管芯面积和处理它们所需的指令位数方面),因此数量通常很少.溢出时的数量发生实时变量(或者,更准确地说,生存区间的数目)在给定的程序点超过可用的寄存器的数量.
考虑以下在具有两个硬件寄存器的假想机器中执行的示例程序.假设除了寄存器分配之外,编译器不执行任何优化.
a := 1 ; liveout: {a}
b := 2 ; liveout: {a,b}
c := 3 ; liveout: {a,b,c}
d := a + b + c
Run Code Online (Sandbox Code Playgroud)
由于a和b用于定义d,它们的有效范围跨越了定义c.但由于机器只有两个寄存器,这是不可能的a,b并且c所有在寄存器中举行,届时d定义.必须至少有一个溢出.
在最简单的溢出形式中,溢出变量的所有定义都被存储替换为堆栈槽,并且所有使用都被替换为负载.某些编译器还可以选择执行寄存器到寄存器溢出,这意味着该值存储到不同类的寄存器中并从其中加载.例如,在x86-64上,编译器可以将来自通用寄存器的值溢出rax到SIMD寄存器中xmm0.这有利于减少内存流量.
作为溢出的替代方法,编译器可以改为执行有效范围分割.这涉及将有效范围分解为较小的部分 - 仅在分割点处插入载荷和存储 - 以使得能够着色其他不可收集的干涉图.
您可以想象,选择哪个溢出变量会对生成的代码的性能产生重大影响.任意溢出在紧密循环中使用或定义的变量可能会带来灾难性的后果.因此,一个好的编译器可能会应用某种形式的启发式方法来估算溢出每个变量的成本,然后再做出选择.