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.

Reply via email to