RISCV32 codegen: small struct passed by value incorrectly (?)
(I don't know how to provide a demo. Do we have some kind of test environment for riscv32? Any ideas?)
ldc2 compiler flags is used:
--mtriple=riscv32-unknown-newlib-elf
--mattr=+zicsr,+zifencei
--fthread-model=local-exec
-g
Code:
// Can be compiled as betterC code
struct Color {
ubyte b;
ubyte g;
ubyte r;
}
struct S {
Color col;
}
extern(C) void main()
{
auto test = Color(255, 0, 0);
S s;
func1(&s, test);
}
// To reproduce it should be implemented in C and compiled by GCC
extern(C) void func1(S* a, Color c) @nogc nothrow
{
// c contains garbage
assert(c.b == 255);
assert(c.g == 0);
assert(c.r == 0);
a.col = c;
}
ldc2 versions: 1.40.0-beta2 and 1.39.0
In RISC-V ABI aN registers are dedicated for arguments
a0 0x3fc98dac a1 0x3fc98d8c a2 0x000000ff
ldc2 passes test value by placing its address into a1, but gcc code awaits whole struct value placed into a1
As I understand ABI, such structures (size less than XLEN) should be passed through the register
Only the CI-tested x86[_64] and AArch64 ABIs are working (i.e., compatible with C, and DMD's custom x86 ABI); there's a 64-bit RISC-V implementation in https://github.com/ldc-developers/ldc/blob/master/gen/abi/riscv64.cpp, but I have no idea about its quality. The C[++] interop tests coverage in the DMD testsuite is pretty good, but needs cross-compiling and running them on actual hardware or in an emulator.