I have a game engine API that is executed as compiled RISC-V. It has been working well until I tried to pass the address of a local struct. The parameter gets optimized away and I'm not sure why. Compiler is GCC 9.2.
This is the particular function used:
inline long syscall(long n, long arg0)
{
register long a0 asm("a0") = arg0;
register long syscall_id asm("a7") = n;
asm volatile ("scall" : "+r"(a0) : "r"(syscall_id));
return a0;
}
Which is called by:
inline void player_init(const PlayerInit& pinit)
{
syscall(ECALL_PLAYER_INIT, (long) &pinit);
}
And the API call itself:
dm::player_init({
.x = 256, .y = 256, .floor = 0,
.direction = 1,
.life = 1,
.maxlife = 24
});
As you can see everything is in order until we read the assembly.
000100f0 <start>:
start():
100f0: fe010113 addi sp,sp,-32
100f4: 00810513 addi a0,sp,8
100f8: 19500893 li a7,405
100fc: 00000073 ecall
Why is the struct itself optimized out? It does set a0 to a seemingly correct location, but it would only contain zeroes. I have also passed other structs like this, which works, but inline assembly can be fickle so I am curious if I'm doing something wrong. It's a very weird problem to have because it does the right thing but the data isn't there!
It's very important that the system calls be inlined.
As a band-aid I have temporarily solved this by making the compiler unaware of what I'm doing with the struct like so:
inline void player_init(const PlayerInit& pinit)
{
asm ("" ::: "memory");
syscall(ECALL_PLAYER_INIT, (long) &pinit);
}
Any ideas would be appreciated.