Kernel/userspace: rework floating point math
SSE is now unconditionally enabled any where and most of math.h is now actually implemented. using __builtin_<func> lead to many hangs where the builtin function would just call itself.
This commit is contained in:
134
userspace/libraries/LibC/fenv.cpp
Normal file
134
userspace/libraries/LibC/fenv.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
#include <fenv.h>
|
||||
|
||||
static uint16_t read_fpu_control_word()
|
||||
{
|
||||
uint16_t control;
|
||||
asm volatile("fstcw %0" : "=m"(control));
|
||||
return control;
|
||||
}
|
||||
|
||||
static uint16_t read_fpu_status_word()
|
||||
{
|
||||
uint16_t status;
|
||||
asm volatile("fstsw %0" : "=m"(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint32_t read_mxcsr()
|
||||
{
|
||||
uint32_t mxcsr;
|
||||
asm volatile("stmxcsr %0" : "=m"(mxcsr));
|
||||
return mxcsr;
|
||||
}
|
||||
|
||||
static void write_fpu_control_word(uint16_t control)
|
||||
{
|
||||
asm volatile("fldcw %0" :: "m"(control));
|
||||
}
|
||||
|
||||
static void write_mxcsr(uint32_t mxcsr)
|
||||
{
|
||||
asm volatile("ldmxcsr %0" :: "m"(mxcsr));
|
||||
}
|
||||
|
||||
int fegetenv(fenv_t* envp)
|
||||
{
|
||||
asm volatile("fstenv %0" : "=m"(envp->x87_fpu));
|
||||
envp->mxcsr = read_mxcsr();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fesetenv(const fenv_t* envp)
|
||||
{
|
||||
if (envp == FE_DFL_ENV)
|
||||
{
|
||||
asm volatile("finit");
|
||||
write_mxcsr(0x1F80);
|
||||
return 0;
|
||||
}
|
||||
|
||||
asm volatile("fldenv %0" :: "m"(envp->x87_fpu));
|
||||
write_mxcsr(envp->mxcsr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fegetround(void)
|
||||
{
|
||||
return (read_fpu_control_word() >> 10) & 0x03;
|
||||
}
|
||||
|
||||
int fesetround(int round)
|
||||
{
|
||||
uint16_t control = read_fpu_control_word();
|
||||
control &= ~(3 << 10);
|
||||
control |= round << 10;
|
||||
write_fpu_control_word(control);
|
||||
|
||||
uint32_t mxcsr = read_mxcsr();
|
||||
mxcsr &= ~(3 << 13);
|
||||
mxcsr |= round << 13;
|
||||
write_mxcsr(mxcsr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int feclearexcept(int excepts)
|
||||
{
|
||||
excepts &= FE_ALL_EXCEPT;
|
||||
|
||||
fenv_t temp_env;
|
||||
fegetenv(&temp_env);
|
||||
temp_env.x87_fpu.status &= ~(excepts | (1 << 7));
|
||||
temp_env.mxcsr &= ~excepts;
|
||||
fesetenv(&temp_env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fetestexcept(int excepts)
|
||||
{
|
||||
excepts &= FE_ALL_EXCEPT;
|
||||
|
||||
const uint16_t status = read_fpu_status_word();
|
||||
const uint32_t mxcsr = read_mxcsr();
|
||||
return (status | mxcsr) & excepts;
|
||||
}
|
||||
|
||||
int feholdexcept(fenv_t*);
|
||||
|
||||
int feraiseexcept(int excepts)
|
||||
{
|
||||
excepts &= FE_ALL_EXCEPT;
|
||||
|
||||
fenv_t temp_env;
|
||||
fegetenv(&temp_env);
|
||||
temp_env.x87_fpu.status |= excepts;
|
||||
fesetenv(&temp_env);
|
||||
asm volatile("fwait");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fegetexceptflag(fexcept_t* flagp, int excepts)
|
||||
{
|
||||
*flagp = fetestexcept(excepts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fesetexceptflag(const fexcept_t* flagp, int excepts)
|
||||
{
|
||||
excepts &= FE_ALL_EXCEPT;
|
||||
|
||||
fenv_t temp_env;
|
||||
fegetenv(&temp_env);
|
||||
temp_env.x87_fpu.status &= ~(FE_ALL_EXCEPT | (1 << 7));
|
||||
temp_env.x87_fpu.status |= *flagp & excepts;
|
||||
fesetenv(&temp_env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int feupdateenv(const fenv_t* envp)
|
||||
{
|
||||
int excepts = fetestexcept(FE_ALL_EXCEPT);
|
||||
fesetenv(envp);
|
||||
feraiseexcept(excepts);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user