When your code deals with the Windows API, it needs to fully support the calling convention used by the Windows API. For Win64, there is only 1 calling convention and that's the fastcall method. It's somewhat of an oddball principle since some registers get preserved (r15 is one) and some don't (r11 among others).
I guess they decided on this to find a balance between what gets preserved and performance.

Regardless, when your code calls into the Win API, it needs to follow the FULL set of rules of the Win API.


Inside your own code, you can use whatever parameter passing rules as you deem best. Even different calling conventions in different bits of code if you really want to, you just need to rigorously follow whatever rules are in place for each function that gets called. And if one fucntion calls another function it's part of that 1st function to properly save/restore whatever is needed to assure that the calling rules of that 1st function are guaranteed.

You really don't need to worry at all about the SYSCALL/SYSRET instructions unless you are using those in your own code (which would mean it's kernel code, which... is somewhat unlikely). Those 2 instructions are somewhat strange in that they don't preserve all registers where you might think they do when compared to how a regular call/ret work.