Skip to content

Commit 3a9a1a2

Browse files
author
Shahab
authored
[SYCL] Fix float to half-type conversion (#1395)
Fix float to half conversion for a range of small numbers that could be represented normally in float, but are subnormal in half-type. Signed-off-by: Shahab Layehgi <[email protected]>
1 parent 3238b3f commit 3a9a1a2

File tree

2 files changed

+25
-31
lines changed

2 files changed

+25
-31
lines changed

sycl/source/half_type.cpp

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,49 +25,39 @@ static uint16_t float2Half(const float &Val) {
2525
const uint32_t Frac32 = Bits & 0x7fffff;
2626
// Extract the exponent from the float value
2727
const uint8_t Exp32 = (Bits & 0x7f800000) >> 23;
28-
const int8_t Exp32Diff = Exp32 - 127;
28+
const int16_t Exp32Diff = Exp32 - 127;
2929

30-
uint16_t Exp16 = 0;
30+
// intialize to 0, covers the case for 0 and small numbers
31+
uint16_t Exp16 = 0, Frac16 = 0;
3132

32-
// convert 23-bit mantissa to 10-bit mantissa.
33-
uint16_t Frac16 = Frac32 >> 13;
34-
// Round the mantissa as given in OpenCL spec section : 6.1.1.1 The half data
35-
// type.
36-
if (Frac32 >> 12 & 0x01)
37-
Frac16 += 1;
38-
39-
if (__builtin_expect(Exp32 == 0xff || Exp32Diff > 15, 0)) {
33+
if (__builtin_expect(Exp32Diff > 15, 0)) {
34+
// Infinity and big numbers convert to infinity
4035
Exp16 = 0x1f;
41-
} else if (__builtin_expect(Exp32 == 0 || Exp32Diff < -14, 0)) {
42-
Exp16 = 0;
43-
} else {
36+
} else if (__builtin_expect(Exp32Diff > -14, 0)) {
37+
// normal range for half type
4438
Exp16 = Exp32Diff + 15;
39+
// convert 23-bit mantissa to 10-bit mantissa.
40+
Frac16 = Frac32 >> 13;
41+
// Round the mantissa as given in OpenCL spec section : 6.1.1.1 The half
42+
// data type.
43+
if (Frac32 >> 12 & 0x01)
44+
Frac16 += 1;
45+
} else if (__builtin_expect(Exp32Diff > -24, 0)) {
46+
// subnormals
47+
Frac16 = (Frac32 | (uint32_t(1) << 23)) >> (-Exp32Diff - 1);
4548
}
4649

47-
if (__builtin_expect(Exp32 == 0xff && Frac32 != 0 && Frac16 == 0, 0)) {
48-
// corner case 1: NaN
49-
// This case happens when FP32 value is NaN whose the fraction part
50-
// transformed to FP16 counterpart is truncated to 0. We need to flip the
51-
// high bit to 1 to make it distinguished from inf.
50+
if (__builtin_expect(Exp32 == 0xff && Frac32 != 0, 0)) {
51+
// corner case: FP32 is NaN
52+
Exp16 = 0x1F;
5253
Frac16 = 0x200;
53-
} else if (__builtin_expect(Exp32 == 0 || (Exp16 == 0x1f && Exp32 != 0xff),
54-
0)) {
55-
// corner case 2: subnormal
56-
// All FP32 subnormal values are under the range of FP16 so the fraction
57-
// part is set to 0.
58-
// corner case 3: overflow
59-
Frac16 = 0;
60-
} else if (__builtin_expect(Exp16 == 0 && Exp32 != 0, 0)) {
61-
// corner case 4: underflow
62-
// We use `truncate` mode here.
63-
Frac16 = 0x100 | (Frac16 >> 2);
6454
}
6555

6656
// Compose the final FP16 binary
6757
uint16_t Ret = 0;
6858
Ret |= Sign;
6959
Ret |= Exp16 << 10;
70-
Ret += Frac16;// Add the carry bit from operation Frac16 += 1;
60+
Ret += Frac16; // Add the carry bit from operation Frac16 += 1;
7161

7262
return Ret;
7363
}
@@ -181,7 +171,7 @@ bool operator==(const half &LHS, const half &RHS) {
181171
}
182172

183173
bool operator!=(const half &LHS, const half &RHS) { return !(LHS == RHS); }
184-
} // namespace half_impl
174+
} // namespace host_half_impl
185175

186176
} // namespace detail
187177
} // namespace sycl

sycl/test/basic_tests/half_type.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@ int main() {
245245
// subnormal
246246
assert(bitwise_comparison_fp16(9.8E-45, 0));
247247
assert(bitwise_comparison_fp16(-9.8E-45, 32768));
248+
uint32_t subnormal_in_16 = 0x38200000;
249+
// verify 0.000038146972 converts to 0.0000382
250+
assert(
251+
bitwise_comparison_fp16(reinterpret_cast<float &>(subnormal_in_16), 0x0280));
248252
// overflow
249253
assert(bitwise_comparison_fp16(half(55504) * 3, 31744));
250254
assert(bitwise_comparison_fp16(half(-55504) * 3, 64512));

0 commit comments

Comments
 (0)