Documentation of saved state and compatible instruction extensions
ColinH opened this issue · 2 comments
There are two assembly implementations of the X86-64 context switching code, one for Windows that saves the necessary GPRs and the XMM registers, and one for other operating systems that only saves the GPRs.
Does this mean that on Linux the assembly switching code is only safe to use for pure integer code that doesn't use any FPU or SIMD instructions? What about on Windows when the 256bit sized YMM registers are used?
If I'm not chasing a red herring and there are restrictions on which instructions can be used in coroutines depending on the chosen context switching implementation then I recommend that these be documented.
- Does this mean that on Linux the assembly switching code is only safe to use for pure integer code that doesn't use any FPU or SIMD instructions?
No, the calling convention between x86_64 Linux ABI and Windows x86_64 ABI is different. On Windows you need to save XMM registers (see https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#callercallee-saved-registers):
- The x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, and XMM6-XMM15 nonvolatile. They must be saved and restored by a function that uses them.
But on x86_64 Linux you don't need to save them (see https://wiki.osdev.org/System_V_ABI) :
Functions preserve the registers rbx, rsp, rbp, r12, r13, r14, and r15;
- What about on Windows when the 256bit sized YMM registers are used?
Actually there was a bug in the past that would save only 64 bits of XMM, it was fixed in #14 , now it saves correctly 128 bits. The Windows calling convention says nothing about needing to save YMM 256bit registers, so we are fine.
- assembly switching code is only safe to use for pure integer code that doesn't use any FPU or SIMD instructions?
It is safe for all platforms, but I cannot say it's a strong safe, because there is a catch that maybe I should document. In the assembly implementation for all platforms I intentionally left out saving of floating point environment, so if you project access the floating point environment (see https://en.cppreference.com/w/c/numeric/fenv) you could have some misbehavior. I intentionally left this out this to save some assembly instructions in the context switch, and because code that access floating point environment is very uncommon, you even need to include that header with #pragma STDC FENV_ACCESS
to enable this feature, it's kinda obscure. But because of this I cannot say that code that uses floating point is all working as expected. I mean things will not crash, but the floating-point rounding and exception flags could be off when doing context switch that access those states. In any case, just avoid doing context switch during code blocks that read/writes the floating point environment.
Thank you for the explanation!