Floating point

Contents

MIPS Floating Point Architecture

MIPS floating point units have 16 double precision and 32 single precision floating point registers. Actually these registers overlap. This means a double precision register can also be used as 2 single precision registers. MIPS II, MIPS III, MIPS IV, MIPS64 and MIPS32 Revision 2 processors have a mode switch which allows to increase the number of double precision registers to 32. The two register models are sometimes referred to as 16/32 and 32/32 by the number of registers available in each of the two modes.

The APIs in the kernel are based on assumptions on the underlying floating point architecture. Therefore Linux doesn't offer an application a choice between 16/32 and 32/32 modes. Instead it will pick a floating point model for a process based on the ABI of the executable.

The Linux kernel and floating point

MIPS floating point units do not support all operations in hardware. A MIPS implementation is free to not implement certain cases in hardware. For example denormalized numbers - that's numbers very close to zero - are not handled in hardware. In such a case MIPS FPU will throw an unimplemented exception and expects the exception handler to do deal with the issue. The software in the Linux kernel handles all this and more, it's capable of fully emulating a hardware floating point unit. That is code built for hardware floating point will always run correctly, even on systems without an FPU.

Note that since Linux 2.4.4 there is no kernel configuration option for the floating point assist / floating point emulator anymore. All kernels contain it as too many people got that choice wrong - any system having an FPU in the hardware must have the FPU emulator to guarantee correct operation.

Software Floating Point

Software floating point keeps floating point values in integer CPU registers and calls subroutines to perform functions that are more or less equivalent to hardware floating point instructions. As the result floating point code built for software floating point is incompatible with hardware floating point, that is can not be linked together statically or dynamically.

GCC

Gcc's mips-linux, mipsel-linux, mips64-linux and mips64el-linux targets default to hardware floating point, that is unless -msoft-float is given they will behave as if a -mhard-float option was given. And that's about all the difference there is between hardware and software floating point configurations of compilers; the rest is in the libraries.

Tradeoffs

Hardware floating point code obviously performs best with a hardware FPU

Software floating point code is the best performing code model on FPU-less processors

Hardware floating point code is somewhat smaller

Software floating point is faster but not hugely faster than the in-kernel emulator. So if floating point performance is critical for overall performance then go for an FPU-full processor. Even the slowest FPU's performance will leave any FPU emulator performance in the dust.

The kernel does not use the FPU other than switching registers con context switch if a thread has actually used the FPU. This means for many systems such as routers the choice between floating point models is rather unimportant and won't show up at all in the overall system performance.