mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-08 04:48:08 +02:00
util/half: Add float_to_half rounding tests
Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41295>
This commit is contained in:
parent
de17328e00
commit
e00a841a9f
1 changed files with 158 additions and 0 deletions
|
|
@ -209,3 +209,161 @@ TEST(float_to_float16_rtz_slow, roundtrip)
|
||||||
{
|
{
|
||||||
test_float_to_half_roundtrip(_mesa_float_to_float16_rtz_slow);
|
test_float_to_half_roundtrip(_mesa_float_to_float16_rtz_slow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum rounding_mode {
|
||||||
|
RTNE,
|
||||||
|
RTZ,
|
||||||
|
RU,
|
||||||
|
RD,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
rand_u32(uint32_t i)
|
||||||
|
{
|
||||||
|
/* Use a prime to generate some pseudo-random bits */
|
||||||
|
return (i + 1) * 2811245417u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t
|
||||||
|
rand_half(uint16_t i)
|
||||||
|
{
|
||||||
|
/* Throw in an almost inf every so often */
|
||||||
|
if (i % 23 == 0)
|
||||||
|
return (i << 15) | 0x7bff;
|
||||||
|
|
||||||
|
/* Throw in a +/-0 every so often */
|
||||||
|
if (i % 23 == 1)
|
||||||
|
return (i << 15);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
i = rand_u32(i);
|
||||||
|
if (!util_is_half_inf_or_nan(i))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the next float16 value, away from zero */
|
||||||
|
static uint16_t
|
||||||
|
next_half(uint16_t h)
|
||||||
|
{
|
||||||
|
/* If it's not inf or nan, we can just add one to the uint16_t */
|
||||||
|
assert(!util_is_half_inf_or_nan(h));
|
||||||
|
return h + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
rand_m_low13(unsigned i)
|
||||||
|
{
|
||||||
|
uint32_t r = rand_u32(rand_u32(i));
|
||||||
|
|
||||||
|
uint32_t m_low13 = r & BITFIELD_MASK(13);
|
||||||
|
|
||||||
|
/* Smash off the bottom 12 every so often */
|
||||||
|
if (((r >> 13) & 0x3) == 0)
|
||||||
|
m_low13 &= ~BITFIELD_MASK(12);
|
||||||
|
|
||||||
|
return m_low13;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_float_to_half_rounding(uint16_t (*func)(float),
|
||||||
|
enum rounding_mode rounding)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < 1024; ++i) {
|
||||||
|
const uint16_t h_rtz = rand_half(i);
|
||||||
|
const bool is_neg = h_rtz & BITFIELD_BIT(15);
|
||||||
|
|
||||||
|
/* Generate a float */
|
||||||
|
union fi f;
|
||||||
|
f.f = _mesa_half_to_float(h_rtz);
|
||||||
|
EXPECT_EQ(f.ui & BITFIELD_MASK(13), 0);
|
||||||
|
|
||||||
|
/* For an exactly representable value, we should get h_rtz back */
|
||||||
|
EXPECT_EQ(func(f.f), h_rtz);
|
||||||
|
|
||||||
|
/* Generate a random non-zero low 13 bits */
|
||||||
|
const uint32_t m_low13 = rand_m_low13(i);
|
||||||
|
if (m_low13 == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (h_rtz & 0x7c00) {
|
||||||
|
f.ui |= m_low13;
|
||||||
|
} else {
|
||||||
|
/* For zero or denormal, we can't just OR in our low bits */
|
||||||
|
float delta = ldexpf(m_low13, -(13 + 10 + 14));
|
||||||
|
if (is_neg)
|
||||||
|
delta = -delta;
|
||||||
|
f.f += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t h_expected;
|
||||||
|
switch (rounding) {
|
||||||
|
case RTNE:
|
||||||
|
if (m_low13 & BITFIELD_MASK(12)) {
|
||||||
|
/* It's not a tie */
|
||||||
|
if (m_low13 & BITFIELD_BIT(12))
|
||||||
|
h_expected = next_half(h_rtz);
|
||||||
|
else
|
||||||
|
h_expected = h_rtz;
|
||||||
|
} else {
|
||||||
|
/* It's a tie because we know m_low13 != 0, round towards even */
|
||||||
|
assert(m_low13 & BITFIELD_BIT(12));
|
||||||
|
if (h_rtz & 1)
|
||||||
|
h_expected = next_half(h_rtz);
|
||||||
|
else
|
||||||
|
h_expected = h_rtz;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTZ:
|
||||||
|
h_expected = h_rtz;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RU:
|
||||||
|
h_expected = is_neg ? h_rtz : next_half(h_rtz);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RD:
|
||||||
|
h_expected = is_neg ? next_half(h_rtz) : h_rtz;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t h_actual = func(f.f);
|
||||||
|
EXPECT_EQ(h_actual, h_expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_to_half, rounding)
|
||||||
|
{
|
||||||
|
test_float_to_half_rounding(_mesa_float_to_half, RTNE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_to_half_slow, rounding)
|
||||||
|
{
|
||||||
|
test_float_to_half_rounding(_mesa_float_to_half_slow, RTNE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_to_float16_rtne, rounding)
|
||||||
|
{
|
||||||
|
test_float_to_half_rounding(_mesa_float_to_float16_rtne, RTNE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_to_float16_rtz, rounding)
|
||||||
|
{
|
||||||
|
test_float_to_half_rounding(_mesa_float_to_float16_rtz, RTZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_to_float16_rtz_slow, rounding)
|
||||||
|
{
|
||||||
|
test_float_to_half_rounding(_mesa_float_to_float16_rtz_slow, RTZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_to_float16_ru, rounding)
|
||||||
|
{
|
||||||
|
test_float_to_half_rounding(_mesa_float_to_float16_ru, RU);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_to_float16_rd, rounding)
|
||||||
|
{
|
||||||
|
test_float_to_half_rounding(_mesa_float_to_float16_rd, RD);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue