Force GCC to return floats in integer registers

108 Views Asked by At

When targeting the x86(-32) architecture, GCC provides a way to completely disable generation of x87 FPU instructions and instead generate calls to library functions which do floating-point math in software. This was historically provided because some early x86 CPUs (i386, i486SX) didn't always have a hardware FPU available. This also proves to be useful in code where the FPU is not available (e.g. kernel code), though usually kernel code doesn't actually use floating-point math at all.

This functionality is easily accessed by using -mgeneral-regs-only, which will disable usage of x87, SSE, AVX and so on. This does require a version of libgcc which contains these routines. It could also technically be done only for x87 by using -msoft-float -mno-fp-ret-in-387 (this would allow to compiler to still make optimizations using SSE, but that's not very useful in this context)

What I want to do is find a way to use this functionality on x86-64. Since x86-64 provides a minimum of SSE2, GCC defaults to that for FP math and -msoft-float does nothing (unless you also set -mfpmath=387, in which case it does generate library calls). The x86-64 ABI also mandates that FP values are passed in XMM registers. This seems to be easily bypassed by using -mgeneral-regs-only, making the compiler pass all FP arguments on the stack and also generate library calls for FP routines.

The problem I face is that the ABI demands that FP values are returned in the XMM register, and there doesn't seem to be any switch to disable that (unlike in x86-32, where it is possible to disable returning in ST0, even though it is also in violation of the ABI). Is there any way to make the compiler return FP values in integer registers?

As you can see in this Godbolt Example, the compiler specifically dislikes returning FP. It doesn't mind passing parameters, which is why the function that takes a double and returns int (as well as the library call to __fixdfsi) works, while the function that returns a double only works in x86-32.

EDIT: It seems that the problem is deeper than I thought. The compiler also refuses to violate the System V ABI for long double, even though it should return in ST0 rather than XMM0. The same exact flags work in 32-bit mode (returns in ecx:edx:eax), but fail in 64-bit mode (specifically, -mno-fp-ret-in-387 does nothing).

0

There are 0 best solutions below