My target is the riscv32-unknown-elf (piccolo32), so it has a stack. The compiler can and will therefore use it.
Code with volatile looks like this:
void* volatile sd = nullptr; // volatile to prevent optimization into register
void* volatile sp = &sd + REGISTER_SIZE; // volatile because sd is **MEHHH***
I don't like to use volatile here, since sp can and should be optimized into a register if possible.
So my question is, how I can retrieve the sp on an risc-v32 without having UB?
I thought that just using
void* sd = nullptr; //may be UB
void* sp = &sd + REGISTER_SIZE;
is UB, since a pointer in c++ is not a pointer to a real hardware location. And that the pointer itself could be optimized away/to any other location the compiler currently likes.
The solution to this problem would be to use
__builtin_stack_address(), like @harold suggested. But clang does not support this intrinsic. Also, some targets of gcc may not support it.The solution for the RISC-V piccolo32 with the target option riscv32-unknown-elf is to write an own version of the intrinsic with inline assembler:
Pure C++ or C solutions inhibit undefined behavior, since they all return an address to local storage. Or they have other issues:
The following for example
does not return an address to local storage, but 2 successive calls to
builtin_stack_addressmay return different values, depending on the allocated stack size and the stores made between those calls:Creates the following asm:
Where the stack pointer is evaluated as sp + 0 and sp + 16. GCC will also evaluate complete different things due to reordering. Therefore, it is never guaranteed to get the actual sp.