这是否意味着只要 __m128 还活着,4 个浮点包就驻留在 xmm 寄存器中?
没有。内在函数由编译器编译,向量变量将像任何其他变量一样进行寄存器分配。
正如您在第二句话中所指出的那样 - 您可以编写具有比寄存器更多的 __m128 变量的代码 - 这会溢出到堆栈。
内在函数 API 旨在让您假装自己在用汇编语言编写,但加载/存储内在函数实际上只是将类型/对齐信息传达给编译器。
(alignof(__m128) = 16,因此任何溢出/重新加载都可以使用需要对齐的指令来完成。重新加载甚至可以将其用作内存源操作数,而不是加载到寄存器中。)
__m128 变量也需要在非内联函数调用中溢出,尤其是在没有调用保留 XMM 寄存器的调用约定中。 (例如 x86-64 System V)。 Windows x64 有几个保留调用的 XMM 寄存器,但有些是易失的(调用破坏的),所以函数有一些 XMM 寄存器可以使用。
因此可以保证__m128 的数量多于可用寄存器的数量会导致溢出,而拥有较少的寄存器总是会避免溢出?
编译器非常努力地按减少溢出的顺序安排指令。例如,在抽象的术语中,您可能会编写如下代码:
int A = *<foo>;
int B = *<foo+1>;
int C = *<foo+2>;
int D = A + B + C;
您可能认为这需要 4 个寄存器,因为您创建并分配了 4 个变量,但很有可能您最终得到的东西在机器级别看起来更像这样:
int A = *<foo>;
int B = *<foo+1>;
int D = A + B
int A = *<foo+2>;
int D = D + A
即编译器已重新排序此代码以最小化所需的物理寄存器数量。
实际上很难预测。编译器旨在降低寄存器压力,因为溢出代价高昂,但可能故意不绝对将其降低到可能的最低水平,因为它们还需要及早获取数据以尝试隐藏内存获取的加载延迟。
一般来说,建议您反汇编高性能代码路径,以确保编译器按照您的预期执行......