https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91229
Bug ID: 91229 Summary: RISC-V ABI problem with zero-length bit-fields and float struct fields Product: gcc Version: 9.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: wilson at gcc dot gnu.org Target Milestone: --- This was noticed by clang development, comparing clang against gcc to verify ABI compliance. There is a problem with the GCC implementation of the ABI, where we are accidentally emitting different code for the same struct when compiled by the C and C++ compilers. There are two cases affected by this. Here is the first example: struct s1 { int : 0; float f; int i; int : 0; }; void dummy(float, int); void f(struct s1 s) { dummy(s.f + 1.0, s.i + 1); } where we have a struct that can be passed in one FP reg and one integer GP, and here is the second example: struct s1 { int : 0; float f; float g; int : 0; }; void dummy(float, float); void f(struct s1 s) { dummy(s.f + 1.0, s.g + 2.0); } where we have a struct that can be passed in two FP regs. In both cases, the C++ compiler passes the float struct fields in FP registers, and the C compiler passes them in integer registers. The general case here is any struct with one or more zero-length bitfields, exactly two non-zero length fields, one of which must have an FP type that can fit in an FP register, and the other can be an FP type that fits in an FP register or an integer type that fits in an integer register or a integer bit-field that is the exact same size as an integer type that can fit in an integer register. Also, the target must have FP register support. The fundamental problem is that the RISC-V backend is not checking for zero-length bit-fields when deciding if a struct field can be passed in a FP register or not. Meanwhile, the C++ front end is stripping zero-length bit-fields after struct layout. So when compiling as C++ we decide that the FP struct fields can be passed in FP regs. But when compiling as C we decide that there are too many struct fields and they all get passed in integer registers. Since having the C and C++ front ends using different ABIs is undesirable, we need an ABI change. Fixing the C++ case would require inconvenient changes to the C++ front end. So fixing the C case with a RISC-V backend patch looks like the best practical solution. The affected structures are a bit obscure and not very useful, so it is hoped no real code will be affected. I've done an open-embedded world build with an instrumented compiler, and I didn't see any case that triggered my code. Not everything built though, since some stuff still doesn't have RISC-V support yet. I did have over 30,000 tasks run, so quite a bit of stuff did build.