#include <math.h>
#include <assert.h>
#include "half_float.h"
#include "util/u_half.h"
#include "rounding.h"
#include "softfloat.h"
#include "macros.h"
typedef union { float f; int32_t i; uint32_t u; } fi_type;
uint16_t
_mesa_float_to_half(float val)
{
const fi_type fi = {val};
const int flt_m = fi.i & 0x7fffff;
const int flt_e = (fi.i >> 23) & 0xff;
const int flt_s = (fi.i >> 31) & 0x1;
int s, e, m = 0;
uint16_t result;
s = flt_s;
if ((flt_e == 0) && (flt_m == 0)) {
e = 0;
}
else if ((flt_e == 0) && (flt_m != 0)) {
e = 0;
}
else if ((flt_e == 0xff) && (flt_m == 0)) {
e = 31;
}
else if ((flt_e == 0xff) && (flt_m != 0)) {
m = 1;
e = 31;
}
else {
const int new_exp = flt_e - 127;
if (new_exp < -14) {
e = 0;
m = _mesa_lroundevenf((1 << 24) * fabsf(fi.f));
}
else if (new_exp > 15) {
e = 31;
}
else {
e = new_exp + 15;
m = _mesa_lroundevenf(flt_m / (float) (1 << 13));
}
}
assert(0 <= m && m <= 1024);
if (m == 1024) {
++e;
m = 0;
}
result = (s << 15) | (e << 10) | m;
return result;
}
uint16_t
_mesa_float_to_float16_rtz(float val)
{
return _mesa_float_to_half_rtz(val);
}
float
_mesa_half_to_float(uint16_t val)
{
return util_half_to_float(val);
}
uint8_t _mesa_half_to_unorm8(uint16_t val)
{
const int m = val & 0x3ff;
const int e = (val >> 10) & 0x1f;
ASSERTED const int s = (val >> 15) & 0x1;
assert(s == 0 && val <= FP16_ONE);
uint32_t v = ((1 << 10) | m) * 255;
v = ((v >> (24 - e)) + 1) >> 1;
return v;
}
uint16_t _mesa_uint16_div_64k_to_half(uint16_t v)
{
if (v < 4)
return v << 8;
#ifdef HAVE___BUILTIN_CLZ
int n = __builtin_clz(v) - 16;
#else
int n = 16;
for (int i = 15; i >= 0; i--) {
if (v & (1 << i)) {
n = 15 - i;
break;
}
}
#endif
int m = ( ((uint32_t)v << (n + 1)) & 0xffff ) >> 6;
int e = 14 - n;
assert(e >= 1 && e <= 30);
assert(m >= 0 && m < 0x400);
return (e << 10) | m;
}