Skip to content
17 changes: 13 additions & 4 deletions projects/clr/hipamd/include/hip/amd_detail/amd_hip_fp8.h
Original file line number Diff line number Diff line change
Expand Up @@ -987,11 +987,20 @@ __FP8_HOST_DEVICE_STATIC__ __hip_fp8_storage_t __hip_cvt_double_to_e8m0(
__hip_fp8_storage_t e8m0;
if (double_exp == 0x0U) {
Comment thread
andrei-kochin marked this conversation as resolved.
Resolved
e8m0 = 0x0U;
} else if ((double_exp - 0x0380U) > 0x00FF) { // if double is NaN/Inf/or too large
e8m0 = hip_detail::e8m0_NaN;
} else {
e8m0 =
double_exp - 0x0380U; // shift due to bias difference between double and single precision
// Use signed arithmetic to avoid unsigned underflow for small normal exponents
// 0x0380 is a bias difference between double and single precision (1023 - 127)
const int float_exp = static_cast<int>(double_exp) - 0x0380;
if (float_exp <= 0) {
// Underflow to subnormal/zero in float domain
e8m0 = 0x0U;
} else if (float_exp > 0x00FF) {
// NaN/Inf or overflow beyond 8-bit exponent range
e8m0 = hip_detail::e8m0_NaN;
} else {
// Valid finite range [1..254], 0xFF yields NaN and is later handled by saturation
Comment thread
andrei-kochin marked this conversation as resolved.
Resolved
e8m0 = static_cast<__hip_fp8_storage_t>(float_exp);
}
}

// If there is a mantissa and the exp wont overflow round up
Expand Down
26 changes: 23 additions & 3 deletions projects/hip-tests/catch/unit/deviceLib/fp8_e8m0.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ THE SOFTWARE.
#include <hip_test_common.hh>
#include <hip/hip_fp8.h>
#include <cmath>
#include <limits>
#include <type_traits>

void host_cvt_bfloat16raw_to_e8m0(const std::vector<__hip_bfloat16>& in,
std::vector<unsigned char>& out, __hip_saturation_t sat,
Expand Down Expand Up @@ -249,6 +251,22 @@ TEST_CASE("Unit__hip_cvt_double_to_e8m0") {
-8.0,
1e38,
-1e38,
// tiny underflow example -> underflows to 0x00
// rounding-to-+Inf promotes to 0x01
1e-50,
-1e-50,
// smallest double-subnormal (denorm_min) -> underflows to 0x00;
// rounding-to-+Inf does not promote (magnitude below half-step)
std::numeric_limits<double>::denorm_min(),
-std::numeric_limits<double>::denorm_min(),
// smallest double-normal -> underflows to 0x00;
// rounding-to-+Inf does not promote (fraction == 0)
std::numeric_limits<double>::min(),
-std::numeric_limits<double>::min(),
// smallest float-normal (cast to double) -> E8M0 code 0x01;
// rounding-to-+Inf does not promote (fraction == 0)
static_cast<double>(std::numeric_limits<float>::min()),
-static_cast<double>(std::numeric_limits<float>::min()),
std::nan("1"),
-std::nan("1"),
std::numeric_limits<double>::infinity(),
Expand All @@ -259,9 +277,11 @@ TEST_CASE("Unit__hip_cvt_double_to_e8m0") {
std::vector<unsigned char> out(exp.size());

if (rounding == hipRoundPosInf) {
exp = {0x00U, 0x7EU, 0x7FU, 0x81U, 0x82U, 0x82U, 0x7EU, 0x7FU, 0x81U, 0x82U, 0x82U, 0xFE, 0xFE};
exp = {0x00U, 0x7EU, 0x7FU, 0x81U, 0x82U, 0x82U, 0x7EU, 0x7FU, 0x81U, 0x82U, 0x82U, 0xFE, 0xFE,
0x01U, 0x01U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x01U};
} else {
exp = {0x00U, 0x7EU, 0x7EU, 0x81U, 0x81U, 0x82U, 0x7EU, 0x7EU, 0x81U, 0x81U, 0x82U, 0xFD, 0xFD};
exp = {0x00U, 0x7EU, 0x7EU, 0x81U, 0x81U, 0x82U, 0x7EU, 0x7EU, 0x81U, 0x81U, 0x82U, 0xFD, 0xFD,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x01U};
}
if (saturation == __HIP_NOSAT) {
std::vector<unsigned char> exp_append = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Expand Down Expand Up @@ -337,7 +357,7 @@ TEST_CASE("Unit__hip_cvt_e8m0_to_bf16raw") {
if (std::isnan(exp[i])) {
REQUIRE(std::isnan(out[i]));
} else {
REQUIRE_THAT(out[i], Catch::WithinAbs(exp[i], 1e-6f) || Catch::WithinRel(exp[i], 1e-3f));
REQUIRE_THAT(out[i], Catch::Matchers::WithinAbs(exp[i], 1e-6f) || Catch::Matchers::WithinRel(exp[i], 1e-3f));
Comment thread
AidanBeltonS marked this conversation as resolved.
Resolved
Comment thread
andrei-kochin marked this conversation as resolved.
Resolved
}
}
}
Expand Down
Loading