我真的想在Linux内核模块中使用浮点运算,只是为了它。我不想做任何花哨的事情,只需使用x87 trig指令和/或sqrt指令,然后将结果分配给变量。这是关于它的。到目前为止,我已经尝试过:
else if(a == 3){
Course course = new Course();
count = count + 11;
for(int j = 0; j<10; j++){
String l = names[(int)(Math.random()*16)];
course.getClasslist()[j].setName(l);//no casting needed
}
array[i]=course;//we can forget the real type of the object now
}
这会失败并产生以下错误:
float sqroot(float arg){
float returnValue;
asm(
"fld %1\n"
"fsqrt\n"
"fst %0"
:"=r"(returnValue)
: "r"(arg)
);
return returnValue;
}
任何和所有帮助将不胜感激。
答案 0 :(得分:1)
使用内核模块中的x87将“正常”,但会静默破坏用户空间x87 / MMX状态。 Why am I able to perform floating point operations inside a Linux kernel module?
您需要 kernel_fpu_begin()
/ kernel_fpu_end()
才能确保安全。
而不是从内联asm加载/存储,请求输入并在x87寄存器堆栈的顶部生成输出,并让编译器在需要时发出加载/存储指令。编译器已经知道如何做到这一点,你只需要为sqrt
指令本身使用内联asm,你可以用这种方式向编译器描述:
static inline
float sqroot(float arg) {
asm("fsqrt" : "+t"(arg) );
return arg;
}
(参见编译器为此on the Godbolt compiler explorer生成的asm)
寄存器约束必须告诉块使用浮点寄存器。
您需要使用-fno-math-errno
将内置实际内联为fsqrt
或sqrtss
,而无需回退到call sqrtf
输入将导致NaN。
static inline
float sqroot_builtin(float arg) {
return __builtin_sqrtf(arg);
}
对于x86-64,我们得到sqrtss %xmm0, %xmm0
/ ret
,而对于i386,我们得到fld
/ fsqrt
/ ret
。 (参见上面的Godbolt链接)。恒定传播通过__builtin_sqrt
和其他优化工作。
编辑:纳入@ iwillnotexist-idontexist的观点(重新加载)。
另外,如果是我,我会在声明中添加static inline
并将其放在头文件中。这将允许编译器更智能地管理寄存器并避免堆栈帧开销。
(我也很想将float
改为double
。否则,你将丢弃实际浮点指令中使用的附加精度。虽然你最终会经常将值存储为float
,会有一条额外的cvtpd2ps
指令。例如,OTOH,如果您将参数传递给printf
,这实际上避免 a cvtps2pd
。)
但Linux内核kprintf
无论如何都没有double
的转换。
如果使用-mfpmath=387
(32位代码的默认值)进行编译,则内联后值将保留在80位x87寄存器中。但是,对于使用64位默认值-mfpmath=sse
的64位代码,这将导致在装回XMM寄存器时四舍五入为float
。
kernel_fpu_begin()
保存完整的FPU状态,避免使用SSE寄存器,只使用x87不会使它或最终的FPU恢复时更便宜地返回用户空间。