Page 1 of 1

Faster context switching on new compilers

Posted: Wed Apr 22, 2026 2:03 am
by bellezzasolo
Newer compilers have introduced a preserve_none calling convention.

On Clang, this is __attribute__((preserve_none)), on MSVC, __preserve_none.

Either way, the result is a calling convention where almost all registers are considered volatile, and is much less verbose than inline assembly register clobbering syntax.

RSP and RBP are non-volatile, and the MSVC version, R12 too. But everything else, if the compiler uses it, the compiler saves it on calling. Of course, floating point registers are volatile already.

The result is a context switch that looks like this:

Code: Select all

;__preserve_none calling convention
;R13 - Current context pointer [save destination, load source]
swap_context_x64@@_A PROC
;Save and restore GPRs
xchg r12, [r13 + CONTEXT_T.rg_r12]

xchg rbp, [r13 + CONTEXT_T.rg_rbp]
xchg rsp, [r13 + CONTEXT_T.rg_rsp]
;Now on the other context stack

;Make the jump
mov rax, [r13 + CONTEXT_T.rg_rip]
mov rdx, finish_pnone
mov [r13 + CONTEXT_T.rg_rip], rdx
push rax
ret
finish_pnone LABEL PROC
ret
swap_context_x64@@_A ENDP

Re: Faster context switching on new compilers

Posted: Wed Apr 22, 2026 8:20 pm
by Octocontrabass
bellezzasolo wrote: Wed Apr 22, 2026 2:03 amOn Clang, this is __attribute__((preserve_none)),
Did you mean "no_callee_saved_registers"? The "preserve_none" attribute also changes parameter passing to match the Glasgow Haskell Compiler, which isn't a stable ABI.
bellezzasolo wrote: Wed Apr 22, 2026 2:03 am

Code: Select all

xchg r12, [r13 + CONTEXT_T.rg_r12]

xchg rbp, [r13 + CONTEXT_T.rg_rbp]
xchg rsp, [r13 + CONTEXT_T.rg_rsp]
Using the XCHG instruction with a memory operand always performs a locked read-modify-write, even without a LOCK prefix. Since your goal is faster context switching, you should probably avoid using the XCHG instruction here.
bellezzasolo wrote: Wed Apr 22, 2026 2:03 am

Code: Select all

;Make the jump
mov rax, [r13 + CONTEXT_T.rg_rip]
mov rdx, finish_pnone
mov [r13 + CONTEXT_T.rg_rip], rdx
push rax
ret
finish_pnone LABEL PROC
ret
What is the purpose of this code? The return address is already on the stack. You can delete all of this and replace it with a single RET.

Re: Faster context switching on new compilers

Posted: Thu Apr 23, 2026 7:03 am
by bellezzasolo
Octocontrabass wrote: Wed Apr 22, 2026 8:20 pm
bellezzasolo wrote: Wed Apr 22, 2026 2:03 amOn Clang, this is __attribute__((preserve_none)),
Did you mean "no_callee_saved_registers"? The "preserve_none" attribute also changes parameter passing to match the Glasgow Haskell Compiler, which isn't a stable ABI.
bellezzasolo wrote: Wed Apr 22, 2026 2:03 am

Code: Select all

xchg r12, [r13 + CONTEXT_T.rg_r12]

xchg rbp, [r13 + CONTEXT_T.rg_rbp]
xchg rsp, [r13 + CONTEXT_T.rg_rsp]
Using the XCHG instruction with a memory operand always performs a locked read-modify-write, even without a LOCK prefix. Since your goal is faster context switching, you should probably avoid using the XCHG instruction here.
bellezzasolo wrote: Wed Apr 22, 2026 2:03 am

Code: Select all

;Make the jump
mov rax, [r13 + CONTEXT_T.rg_rip]
mov rdx, finish_pnone
mov [r13 + CONTEXT_T.rg_rip], rdx
push rax
ret
finish_pnone LABEL PROC
ret
What is the purpose of this code? The return address is already on the stack. You can delete all of this and replace it with a single RET.
This was a simple coroutine proof of concept, with an embedded ARM environment eventually in mind (to do some work on the occurence of an interrupt). Thus, minimising context size was a factor, and I went with xchg to keep the logic clearer, while still functional.

no_callee_saved_registers is the GCC equivalent, yes.

As for the ret, hmm, good point! I didn't think through the stack swapping fully there.

Re: Faster context switching on new compilers

Posted: Thu Apr 23, 2026 7:26 pm
by Octocontrabass
bellezzasolo wrote: Thu Apr 23, 2026 7:03 amno_callee_saved_registers is the GCC equivalent, yes.
No it isn't. Those are two different attributes that do two different (but similar) things.