What is the simplest way to work with big-endian values in RISC-V at the assembly language level? That is, how to load a big-endian value from memory into a register, work w
The RISC-V ISA has no explicit byte swapping instructions. Your best bet is to use a C builtin to perform this calculation, which in GCC land would be something like __builtin_bswap32()
. This gives the compiler the most information possible so it can make good decisions. With the current set of defined ISAs you'll almost certainly end up calling into a routine, but if a B extension is ever defined you will transparently get better generated code. The full set of defined builtins is availiable online: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html .
If you're stuck doing this in assembly, then your best bet is to call into an existing byte swap routine. The canonical one for a 32-bit swap is __bswapsi2
, which is part of libgcc -- you're probably using that anyway, so it'll be around. That's what the compiler currently does so all you're losing is eliding the function call when there's a better implementation available.
As a concrete example, here's my example C function
unsigned swapb(unsigned in) { return __builtin_bswap32(in); }
and the generated assembly
swapb:
addi sp,sp,-16
sd ra,8(sp)
call __bswapsi2
ld ra,8(sp)
sext.w a0,a0
addi sp,sp,16
jr ra