rv64g initial import#364
Conversation
|
Thanks! We're certainly interested in having this. This is a fairly critical section of the code though, so review will take a bit longer. |
|
Glad to hear there's interest. I'll double back on the smaller issues. The code passes |
|
Great question! As best I can tell, the correct behavior for the various registers depends on the calling convention for the platform. From the perspective of the end-user, the context swap appears to happen inside an opaque function call. The context swap is supposed to save/restore whatever context is saved/restored by a callee and not cleared away by the caller. It doesn't have to worry about clearing away state that is saved/restored by the caller. I don't know offhand which case applies on RISC-V. |
|
I'll add flags to the build system that allow users to add in floating point and/or vector support for context switching. |
|
@insertinterestingnamehere turns out there was a small error in the build script and it looks like I've several fixes to submit later today. |
insertinterestingnamehere
left a comment
There was a problem hiding this comment.
I'm still working through the assembly, but here's a few comments on everything else.
include/fastcontext/riscv-ucontext.h
Outdated
|
|
||
| struct mctxt { | ||
| /* Saved main processor registers. */ | ||
| #ifdef NEEDARMA64CONTEXT |
There was a problem hiding this comment.
This is just re-using the same mctxt that's used for ARM, and I'm not sure that's right. The NEEDARMA64CONTEXT macro should never be set here and it appears the corresponding assembly is saving more than 16 registers (like it would in the 32-bit case) so this seems wrong.
|
|
||
| // sigset_t uc_sigmask; | ||
| mctxt_t mc; | ||
| struct uctxt *uc_link; /* unused */ |
There was a problem hiding this comment.
Don't worry about this for this PR, but I need to remember to come back and remove these uc_link struct members. At a glance it looks like they're only ever used if we're using the system swapcontext. If that's actually the case, we should only include them in that case.
include/qt_atomics.h
Outdated
| do { __asm__ __volatile__("yield" ::: "memory"); } while (0) | ||
| #elif QTHREAD_ASSEMBLY_ARCH == QTHREAD_RISCV | ||
| #define SPINLOCK_BODY() \ | ||
| do { atomic_thread_fence(memory_order_acq_rel); } while (0) |
There was a problem hiding this comment.
This is not right. It should be some kind of pause instruction, not a memory fence. The fences are handled elsewhere.
There was a problem hiding this comment.
I chased this down a bit more. The correct assembly seems to be the same as the AMD64 branch. The only catch is that clang needs explicit permission to use the zihintpause extension so -march=rv64g_zihintpause or something like it needs to be spun into the CMake file. I'm fine taking care of this later, but I figured I'd mention of it in case you're using clang.
There was a problem hiding this comment.
cleaned this one up.
src/cacheline.c
Outdated
| static int cacheline_bytes = 0; | ||
|
|
||
| #define MAX(a, b) (((a) > (b)) ? (a) : (b)) | ||
| #if defined(__riscv) |
There was a problem hiding this comment.
Please include this as a part of the big if/elif/elif... below instead of nesting the ifdefs further
Sounds great. Thank you!
My point wasn't that we needed an option, it's that we need to check the documented behavior for those registers in the Linux/RISC-V calling convention. Unfortunately I don't know offhand. When I manage to chase down more exact details on this I'll let you know. |
|
Okay, I think we don't need to save the floating point registers because the calling convention is that unused registers for function calls get clobbered anyway. See https://stackoverflow.com/a/69317525. The verbiage from the spec is "In addition to the argument and return value registers, seven integer registers t0–t6 and twelve |
|
@insertinterestingnamehere yep, you are seeing all the little things I should have caught with better due diligence on the output from the cmake build configuration output 😉 |
|
Alright, I have the "which registers" thing pinned down. Table 18.2 in https://riscv.org/wp-content/uploads/2024/12/riscv-calling.pdf is probably the most helpful thing for figuring out which registers need to be preserved. Only registers listed as being saved by the callee need to be saved for the context swap. This means that a few of the floating point registers do need to be saved, but several of the integer registers actually do not. |
|
@insertinterestingnamehere contacted you via email for some implementation questions |
Thanks, that somehow ended up in the wrong folder. Happy to field questions there now. |
|
@insertinterestingnamehere happy new year! managed to fix the software; apologies for the delay on this one. I took a crack at following the calling conventions and got some segmentation faults. I've modified the code to work with the full register file and it executes correctly. |
spacing corrections and removed incorrect comments.
|
@insertinterestingnamehere alright, was finally able to minimize the instruction count and memory buffer size for context switching. 🎸 |
|
Okay, this looks great! Thank you! I've confirmed this works. The CI failures all appear unrelated. I'll merge once the remaining CI runs finish. |
176bd56
into
sandialabs:main
|
@insertinterestingnamehere amazing! Much appreciated! |
generic risc-v support for
g(short hand for theimafdcbase extensions)