2

我写了一个简单的协作多线程库。目前,我总是在切换到新上下文时使用fxsave/保存和恢复 fpu 状态。fxrstor但这在 cdecl 调用约定中是必要的吗?

举个简单的例子:

float thread_using_fpu(float x)
{
    float y = x / 2; // do some fpu operation
    yield();         // context switch, possibly altering fpu state.
    y = y / 2;       // another fpu operation
    return y;
}

编译器可以在调用后对 FPU 状态做出任何假设yield()吗?

4

2 回答 2

3

根据SYSTEM V 应用程序二进制接口 Intel386TM 架构处理器补充,第 3-12 页:

%st(0):如果函数没有返回浮点值,那么这个寄存器必须是空的。在进入函数之前,该寄存器必须为空。

%st(1) 到 %st(7):浮点暂存寄存器在标准调用序列中没有指定角色。这些寄存器在进入函数之前和退出函数时必须为空。

因此,您不需要上下文切换它们。

另一个较新的版本是这样说的:

进入功能后,CPU 应处于 x87 模式。因此,每个使用 MMX 寄存器的函数都需要在使用 MMX 寄存器之后,在返回或调用另一个函数之前发出 emms 或 femms 指令。[...] MXCSR 寄存器的控制位是被调用者保存的(跨调用保留),而状态位是调用者保存的(不保留)。x87 状态字寄存器是调用者保存的,而 x87 控制字是被调用者保存的。[...] 所有 x87 寄存器都是调用者保存的,因此使用 MMX 寄存器的被调用者可以使用更快的 femms 指令。

因此,您可能需要保存控制字。

于 2016-03-12T23:53:40.453 回答
2

不,您不必对状态进行任何保存。如果一个线程处于浮点计算的中间,例如设置了非规范化标志,并且该线程被中断,那么当它恢复时,O/S 或内核将设置标志,就像它会恢复一样其他寄存器。同样,您不必在 yield() 中担心它。

编辑:如果您正在进行自己的上下文切换,则可能需要保存精度和舍入控制标志,如果您需要将它们设置为非默认值。否则,你又没事了。

于 2016-03-12T22:32:44.563 回答