Understandable the architecture calling conventions are important - if registers are marked as destroyed you must treat them as such, even if in your code it seems they’re preserved.
Single-stepping debuggers have caused weird side effects in the past (the trap instruction coincidentally keeps a register with a “sane” value and so it’s not noticed that in normal operation it gets scrambled).
Note that the base RISC-V ISA (IMA extensions) doesn't say anything about calling conventions or functions (calls and returns) or even a stack. All X registers except X0 are interchangeable.
Which registers are caller save or callee save or even which is the stack pointer or function return address is all purely a software convention in a particular OS and/or compiler.
(the C extension gives greater program compression if used with an ABI that uses X1 as the Return Address and X2 as the Stack Pointer, and X8-X15 as the most commonly used registers, but even then nothing breaks if you don't)
This is imprecise wrt the point of view of caller vs callee.
> All a (argument) and t (temporary) registers must be considered destroyed after a function call.
All s (saved) registers can be considered saved after a function call.
Who must do the considering here? The caller or the callee? I expect it's the caller because that makes the most sense, but I'd like to see it spelled out.
If my assumption is correct, that implies that callees are required to restore the s registers before returning but they are not required to restore a or t registers before returning. Correct?