Faster context switching on new compilers

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
bellezzasolo
Member
Member
Posts: 163
Joined: Sun Feb 20, 2011 2:01 pm

Faster context switching on new compilers

Post 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
Whoever said you can't do OS development on Windows?
https://github.com/ChaiSoft/ChaiOS
Octocontrabass
Member
Member
Posts: 6248
Joined: Mon Mar 25, 2013 7:01 pm

Re: Faster context switching on new compilers

Post 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.
User avatar
bellezzasolo
Member
Member
Posts: 163
Joined: Sun Feb 20, 2011 2:01 pm

Re: Faster context switching on new compilers

Post 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.
Whoever said you can't do OS development on Windows?
https://github.com/ChaiSoft/ChaiOS
Octocontrabass
Member
Member
Posts: 6248
Joined: Mon Mar 25, 2013 7:01 pm

Re: Faster context switching on new compilers

Post 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.
Post Reply