13

I am in the following situation:

  • I am writing code for a kernel that does not allow SSE instructions
  • I need to do floating-point arithmetic
  • I'm compiling for a x86_64 platform

Here is a code sample that illustrates the problem:

int
main(int argc, char** argv)
{
    double d = 0.0, dbase;
    uint64_t base_value = 300;

    d = (2200.0 - 1000.0)/(1000.0);
    dbase = d * base_value;
    printf("d = %f, dbase = %f\n", d, dbase);
    base_value = dbase;
    printf("base_value = %llu\n", (long long unsigned)base_value);
    return 0;
}

And here is the relevant line from the makefile:

CFLAGS +=   -mcmodel=kernel -mno-red-zone -mfpmath=387 -mno-sse -mno-sse2 -mno-mmx -mno-3dnow \
            -msoft-float -fno-asynchronous-unwind-tables -fno-omit-frame-pointer

When I run a build I get this error:

SSE register return with SSE disabled

(The error points to the line that multiplies d and base_value)

Any idea what I can do to fix this? Removing -mno-sse is not an option, but it seems like the compiler should be able to generate non-sse code to do the multiply.

Thanks Nathan

Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
Nathan
  • 1,218
  • 3
  • 19
  • 35
  • 1
    It's possible that gcc can't handle this case because it assumes all x86-64 processors have SSE. – Amok Oct 12 '09 at 18:48
  • 1
    Does this mean that nobody ever multiplies anything inside the FreeBSD kernel on 64-bit builds? – Nathan Oct 12 '09 at 18:53
  • Any kernel I've worked on tends to avoid floating point as much as possible. – Carl Norum Oct 12 '09 at 18:57
  • Carl, I wonder why that is. Are the FP registers usually not saved on mode switch? – avakar Oct 12 '09 at 19:33
  • 3
    Yeah. Kernel folks hate needing to save and restore more registers. – Stephen Canon Oct 12 '09 at 19:40
  • 3
    gcc can do x87 math just fine (if you tell the kernel to save/restore the user-space x87 FPU state). The problem is passing `double` as a function arg, since you're compiling for a calling convention that passes `double` args in XMM registers. If you leave out the `printf("d = %f, dbase = %f\n", d, dbase);`, you can write functions that use FP math even with `-mno-sse`: e.g. see https://godbolt.org/g/oIM1rS for asm output from a simple function. – Peter Cordes Nov 29 '16 at 11:19

2 Answers2

10

It sounds like the compiler is emitting a call to a library routine to do the floating point multiply for you (presumably without using SSE), but is trying to use an ABI for the call that has the return value passed in SSE. Obviously, that doesn't work.

If it is possible at all to use floating-point at all in your kernel, there should be a special runtime library to do soft-float operations that does not use the usual (userland) argument passing and return conventions. However, as far as I know, there is no support for floating-point in the BSD kernel. That was certainly the case a few years ago.

You should probably just ask the BSD kernel dev email list whether or not it is possible to use floating-point; I suspect it will give you a faster more definitive answer than SO.

Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
  • I decided to just use fixed-point arithmetic instead (the kernel in question is based off the FreeBSD kernel but is significantly altered, so I wasn't sure that any of the official mailing lists would give a better answer than "don't do that". – Nathan Oct 12 '09 at 22:05
  • Ah. Sorry that there's not a happier answer for this one. – Stephen Canon Oct 12 '09 at 23:13
0

As I know the kernel does not use SSE often, but you can turn on SSE for just the module or application build if the architecture supports it.

For me I checked the cpu with: cat /proc/cpuinfo | grep --color -i sse, if I can see any sse related flags or potions (if any). If you got back any results, then thats good, now you can see witch sse versions are available like: sse sse2 sse3 sse4.

After inspection you can add the following flags to the Makefile or the builder like:

CFLAGS += -msoft-float -msse -msse2 -msse3 -msse4

or like:

EXTRA_CFLAGS := -msoft-float -msse -msse2 -msse3 -msse4

I run into this issue using a newer gen Intel Atom processor on kervel version 5.5.7 using Debian.

Radle
  • 1
  • 1
    You can't *safely* do this for kernel code, unless all the functions in this file are only ever called from other functions that used `kernel_fpu_begin()` before calling, and will use `kernel_fpu_end()` sometime after. See [Why am I able to perform floating point operations inside a Linux kernel module?](https://stackoverflow.com/q/15883947). Normally Linux builds with `-mgeneral-regs-only` (on new enough GCC) so FP math or SIMD is only possible with `__attribute__((target(...)))` or inline asm. – Peter Cordes May 20 '22 at 14:23