Compiler construction 编译器中的寄存器分配
在编译器后端必须将变量分配给内存或寄存器的代码生成的寄存器分配阶段出现的寄存器溢出或溢出代码是什么意思 非常昂贵(就芯片面积和寻址所需的指令位数量而言),因此通常数量很少。当给定程序点的数量(或者更准确地说,活动范围的数量)超过可用寄存器的数量时发生 考虑以下示例程序在具有两个硬件寄存器的虚拟机中执行。假设编译器除了寄存器分配之外不执行任何优化Compiler construction 编译器中的寄存器分配,compiler-construction,code-generation,cpu-registers,Compiler Construction,Code Generation,Cpu Registers,在编译器后端必须将变量分配给内存或寄存器的代码生成的寄存器分配阶段出现的寄存器溢出或溢出代码是什么意思 非常昂贵(就芯片面积和寻址所需的指令位数量而言),因此通常数量很少。当给定程序点的数量(或者更准确地说,活动范围的数量)超过可用寄存器的数量时发生 考虑以下示例程序在具有两个硬件寄存器的虚拟机中执行。假设编译器除了寄存器分配之外不执行任何优化 a := 1 ; liveout: {a} b := 2 ; liveout: {a,b} c := 3 ; liveout: {a,b,c
a := 1 ; liveout: {a}
b := 2 ; liveout: {a,b}
c := 3 ; liveout: {a,b,c}
d := a + b + c
由于a
和b
用于d
的定义中,因此它们的有效范围与c
的定义交叉。但是,由于机器只有两个寄存器,当定义了d
时,a
、b
和c
不可能全部保存在寄存器中。必须至少有一个溢出
在最简单的溢出形式中,溢出变量的所有定义都替换为插槽中的存储,所有使用都替换为加载。一些编译器还可以选择执行寄存器到寄存器溢出,这意味着值存储到不同类的寄存器中并从中加载。例如,在x86-64上,编译器可以将值从通用寄存器(如rax
)溢出到SIMD寄存器(如xmm0
)中。这有减少内存流量的好处
作为溢出的替代方法,编译器可以执行活动范围拆分。这涉及到将活动范围分割成更小的部分——仅在分割点插入负载和存储——以使原本不可着色的干涉图着色
正如您可能想象的那样,选择哪一个变量溢出对结果代码的性能有重大影响。任意泄漏紧循环中使用或定义的变量可能会产生灾难性后果。因此,一个好的编译器可能会在做出选择之前应用某种形式的启发式方法来估计溢出每个变量的成本。令人敬畏的解释,所以编译器也使用启发式方法来估计寄存器溢出?令人惊讶的是,你能指出一些关于启发式算法的资源吗。谢谢,我投了赞成票。我还没有找到关于这个的任何可访问的资源。建议可以使用循环嵌套作为估计。基本上,我们假设每个循环执行N次(我们可以选择N=10)。因此,循环中引用的变量的成本是存储和加载它所需的内存操作数的N倍。类似地,在双嵌套循环中引用的变量的开销将是操作数的N^2倍。