SUBmarinoff February 2016

Operand type mismatch in x87 inline assembly in a Linux kernel module

I really want to use floating point arithmetic in a Linux kernel module, just for the heck of it. I don't want to do anything fancy, just use the x87 trig instructions and/or the sqrt instruction, then assign the result to a variable. That's about it. So far, I've tried:

float sqroot(float arg){
    float returnValue;
    asm(
     "fld %1\n"
     "fsqrt\n"
     "fst %0"
     :"=r"(returnValue) 
     : "r"(arg)
    );
    return returnValue;
}

This fails miserably and yields the following error:

Error: operand type mismatch for `fld'
Error: operand type mismatch for `fst'

Any and all help will be appreciated.

Answers


Gil Hamilton February 2016

Looks like this works:

float sqroot(float arg) {
    float returnValue;
    asm(
        "fsqrt\n"
    :"=&t"(returnValue)
    : "t"(arg)
    );
    return returnValue;
}

The register constraints have to tell the block to use the floating point registers.

EDIT: Incorporating @iwillnotexist-idontexist's point (re double loading).

Also, if it were me, I'd add static inline to the declaration and put it in a header file. This will allow the compiler to more intelligently manage registers and avoid stack frame overheads.

(I'd also be tempted to change float to double throughout. Otherwise, you're discarding the additional precision that is used in the actual floating point instructions. Although if you will end up frequently storing the values as float, there will be an additional cvtpd2ps instruction. OTOH, if you're passing arguments to printf, for example, this actually avoids a cvtps2pd.)

Post Status

Asked in February 2016
Viewed 1,501 times
Voted 12
Answered 1 times

Search




Leave an answer