Files
korenkonder_ReDIVA/src/KKdLib/half_t.cpp
T
2022-07-06 14:13:11 +03:00

110 lines
3.2 KiB
C++

/*
by korenkonder
GitHub/GitLab: korenkonder
*/
#include "half_t.hpp"
#include <immintrin.h>
extern bool f16c;
inline half_t load_reverse_endianness_half_t(void* ptr) {
return (half_t)_byteswap_ushort(*(uint16_t*)ptr);
}
inline void store_reverse_endianness_half_t(half_t value, void* ptr) {
*(half_t*)ptr = (half_t)_byteswap_ushort((uint16_t)value);
}
inline half_t reverse_endianness_half_t(half_t value) {
return (half_t)_byteswap_ushort((uint16_t)value);
}
float_t half_to_float(half_t h) {
if (f16c)
return _mm_cvtss_f32( _mm_cvtph_ps(_mm_cvtsi32_si128((uint16_t)h)));
int32_t si32;
uint16_t sign = (h >> 15) & 0x001;
uint16_t exponent = (h >> 10) & 0x01F;
uint16_t mantissa = h & 0x3FF;
si32 = sign ? (int32_t)0x80000000 : 0x00000000;
if (exponent == 0x1F)
si32 |= 0x7F800000;
else if (exponent != 0x00)
si32 |= ((int32_t)exponent - 0x0F + 0x7F) << 23;
si32 |= (int32_t)mantissa << 13;
return *(float_t*)&si32;
}
half_t float_to_half(float_t val) {
if (f16c)
return (half_t)_mm_cvtsi128_si32(_mm_cvtps_ph(_mm_set_ss(val), _MM_FROUND_CUR_DIRECTION));
int32_t si32 = *(int32_t*)&val;
if (si32 == 0x00000000)
return FLOAT16_POSITIVE_ZERO;
else if ((uint64_t)si32 == 0x80000000)
return FLOAT16_NEGATIVE_ZERO;
int16_t sign = (int16_t)((si32 >> 31) & 0x001);
int16_t exponent = (int16_t)((si32 >> 23) & 0x0FF);
int16_t mantissa = (int16_t)((si32 >> 13) & 0x3FF);
if (exponent == 0xFF)
exponent = 0x1F;
else if (exponent != 0x00) {
exponent -= 0x7F - 0x0F;
if (exponent < 0x00)
exponent = mantissa = 0;
else if (exponent >= 0x1F)
exponent = 0x1F;
}
return (half_t)((sign << 15) | (exponent << 10) | mantissa);
}
double_t half_to_double(half_t h) {
if (f16c)
return _mm_cvtss_f32(_mm_cvtph_ps(_mm_cvtsi32_si128((uint16_t)h)));
int64_t si64;
uint16_t sign = (h >> 15) & 0x001;
uint16_t exponent = (h >> 10) & 0x01F;
uint16_t mantissa = h & 0x3FF;
si64 = sign ? (int64_t)0x8000000000000000 : 0x0000000000000000;
if (exponent == 0x1F)
si64 |= 0x7FF0000000000000;
else if (exponent != 0x00)
si64 |= ((int64_t)exponent - 0x0F + 0x3FF) << 52;
si64 |= (int64_t)mantissa << 42;
return *(double_t*)&si64;
}
half_t double_to_half(double_t val) {
if (f16c)
return (half_t)_mm_cvtsi128_si32(_mm_cvtps_ph(_mm_cvtpd_ps(_mm_set_sd(val)), _MM_FROUND_CUR_DIRECTION));
int64_t si64 = *(int64_t*)&val;
if (si64 == 0x0000000000000000)
return FLOAT16_POSITIVE_ZERO;
else if ((uint64_t)si64 == 0x8000000000000000)
return FLOAT16_NEGATIVE_ZERO;
int16_t sign = (int16_t)((si64 >> 63) & 0x001);
int16_t exponent = (int16_t)((si64 >> 52) & 0x7FF);
int16_t mantissa = (int16_t)((si64 >> 42) & 0x3FF);
if (exponent == 0x7FF)
exponent = 0x1F;
else if (exponent != 0x00) {
exponent -= 0x3FF - 0x0F;
if (exponent < 0x00)
exponent = mantissa = 0;
else if (exponent >= 0x1F)
exponent = 0x1F;
}
return (half_t)((sign << 15) | (exponent << 10) | mantissa);
}