https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92821
Bug ID: 92821 Summary: Miscompilation when passing 8-bit enum to extern function Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: emilio at crisal dot io Target Milestone: --- Created attachment 47427 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47427&action=edit Test-case that reproduces the bug with gcc 7.4 and -Os We've seen a miscompilation of Firefox in GCC 7.4 when compiled with -Os, when we pass an `enum class : uint8_t` to an extern function. See https://bugzilla.mozilla.org/show_bug.cgi?id=1600735 for all the details. It seems fixed in GCC 8. Bisection by redi (thanks!) points to https://gcc.gnu.org/PR82260 as the culprit for the fix, which seems just a missed optimization opportunity (thus me filing this bug). The basic setup is just calling an extern function with an `enum class : uint8_t` argument, and having that extern function compiled by LLVM (in this case, by the Rust compiler). LLVM seems to rely on the caller zero-extending the enum to 32 bits. Per bug 46942 it seems gcc also does something like this usually (and it does happen to be the case for non -Os builds). In the bad case, GCC uses a single `mov sil,bl` to set up the argument, which means garbage on the rest of the register remains that LLVM assumes to be zeroed. It seems either GCC should probably always zero-extend when calling an extern function, or LLVM should never rely on this zero-extension... I don't know what the relevant ABI specifications say, but I'm happy to file an LLVM bug if this is deemed not to be a GCC bug per se.