xref: /aosp_15_r20/external/OpenCL-Headers/CL/cl_half.h (revision 3cc257528f335c5672e46865a03b8ee020e5fe2d)
1*3cc25752SFrank Piva /*******************************************************************************
2*3cc25752SFrank Piva  * Copyright (c) 2019-2020 The Khronos Group Inc.
3*3cc25752SFrank Piva  *
4*3cc25752SFrank Piva  * Licensed under the Apache License, Version 2.0 (the "License");
5*3cc25752SFrank Piva  * you may not use this file except in compliance with the License.
6*3cc25752SFrank Piva  * You may obtain a copy of the License at
7*3cc25752SFrank Piva  *
8*3cc25752SFrank Piva  *    http://www.apache.org/licenses/LICENSE-2.0
9*3cc25752SFrank Piva  *
10*3cc25752SFrank Piva  * Unless required by applicable law or agreed to in writing, software
11*3cc25752SFrank Piva  * distributed under the License is distributed on an "AS IS" BASIS,
12*3cc25752SFrank Piva  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*3cc25752SFrank Piva  * See the License for the specific language governing permissions and
14*3cc25752SFrank Piva  * limitations under the License.
15*3cc25752SFrank Piva  ******************************************************************************/
16*3cc25752SFrank Piva 
17*3cc25752SFrank Piva /**
18*3cc25752SFrank Piva  * This is a header-only utility library that provides OpenCL host code with
19*3cc25752SFrank Piva  * routines for converting to/from cl_half values.
20*3cc25752SFrank Piva  *
21*3cc25752SFrank Piva  * Example usage:
22*3cc25752SFrank Piva  *
23*3cc25752SFrank Piva  *    #include <CL/cl_half.h>
24*3cc25752SFrank Piva  *    ...
25*3cc25752SFrank Piva  *    cl_half h = cl_half_from_float(0.5f, CL_HALF_RTE);
26*3cc25752SFrank Piva  *    cl_float f = cl_half_to_float(h);
27*3cc25752SFrank Piva  */
28*3cc25752SFrank Piva 
29*3cc25752SFrank Piva #ifndef OPENCL_CL_HALF_H
30*3cc25752SFrank Piva #define OPENCL_CL_HALF_H
31*3cc25752SFrank Piva 
32*3cc25752SFrank Piva #include <CL/cl_platform.h>
33*3cc25752SFrank Piva 
34*3cc25752SFrank Piva #include <stdint.h>
35*3cc25752SFrank Piva 
36*3cc25752SFrank Piva #ifdef __cplusplus
37*3cc25752SFrank Piva extern "C" {
38*3cc25752SFrank Piva #endif
39*3cc25752SFrank Piva 
40*3cc25752SFrank Piva 
41*3cc25752SFrank Piva /**
42*3cc25752SFrank Piva  * Rounding mode used when converting to cl_half.
43*3cc25752SFrank Piva  */
44*3cc25752SFrank Piva typedef enum
45*3cc25752SFrank Piva {
46*3cc25752SFrank Piva   CL_HALF_RTE, // round to nearest even
47*3cc25752SFrank Piva   CL_HALF_RTZ, // round towards zero
48*3cc25752SFrank Piva   CL_HALF_RTP, // round towards positive infinity
49*3cc25752SFrank Piva   CL_HALF_RTN, // round towards negative infinity
50*3cc25752SFrank Piva } cl_half_rounding_mode;
51*3cc25752SFrank Piva 
52*3cc25752SFrank Piva 
53*3cc25752SFrank Piva /* Private utility macros. */
54*3cc25752SFrank Piva #define CL_HALF_EXP_MASK 0x7C00
55*3cc25752SFrank Piva #define CL_HALF_MAX_FINITE_MAG 0x7BFF
56*3cc25752SFrank Piva 
57*3cc25752SFrank Piva 
58*3cc25752SFrank Piva /*
59*3cc25752SFrank Piva  * Utility to deal with values that overflow when converting to half precision.
60*3cc25752SFrank Piva  */
cl_half_handle_overflow(cl_half_rounding_mode rounding_mode,uint16_t sign)61*3cc25752SFrank Piva static inline cl_half cl_half_handle_overflow(cl_half_rounding_mode rounding_mode,
62*3cc25752SFrank Piva                                               uint16_t sign)
63*3cc25752SFrank Piva {
64*3cc25752SFrank Piva   if (rounding_mode == CL_HALF_RTZ)
65*3cc25752SFrank Piva   {
66*3cc25752SFrank Piva     // Round overflow towards zero -> largest finite number (preserving sign)
67*3cc25752SFrank Piva     return (sign << 15) | CL_HALF_MAX_FINITE_MAG;
68*3cc25752SFrank Piva   }
69*3cc25752SFrank Piva   else if (rounding_mode == CL_HALF_RTP && sign)
70*3cc25752SFrank Piva   {
71*3cc25752SFrank Piva     // Round negative overflow towards positive infinity -> most negative finite number
72*3cc25752SFrank Piva     return (1 << 15) | CL_HALF_MAX_FINITE_MAG;
73*3cc25752SFrank Piva   }
74*3cc25752SFrank Piva   else if (rounding_mode == CL_HALF_RTN && !sign)
75*3cc25752SFrank Piva   {
76*3cc25752SFrank Piva     // Round positive overflow towards negative infinity -> largest finite number
77*3cc25752SFrank Piva     return CL_HALF_MAX_FINITE_MAG;
78*3cc25752SFrank Piva   }
79*3cc25752SFrank Piva 
80*3cc25752SFrank Piva   // Overflow to infinity
81*3cc25752SFrank Piva   return (sign << 15) | CL_HALF_EXP_MASK;
82*3cc25752SFrank Piva }
83*3cc25752SFrank Piva 
84*3cc25752SFrank Piva /*
85*3cc25752SFrank Piva  * Utility to deal with values that underflow when converting to half precision.
86*3cc25752SFrank Piva  */
cl_half_handle_underflow(cl_half_rounding_mode rounding_mode,uint16_t sign)87*3cc25752SFrank Piva static inline cl_half cl_half_handle_underflow(cl_half_rounding_mode rounding_mode,
88*3cc25752SFrank Piva                                                uint16_t sign)
89*3cc25752SFrank Piva {
90*3cc25752SFrank Piva   if (rounding_mode == CL_HALF_RTP && !sign)
91*3cc25752SFrank Piva   {
92*3cc25752SFrank Piva     // Round underflow towards positive infinity -> smallest positive value
93*3cc25752SFrank Piva     return (sign << 15) | 1;
94*3cc25752SFrank Piva   }
95*3cc25752SFrank Piva   else if (rounding_mode == CL_HALF_RTN && sign)
96*3cc25752SFrank Piva   {
97*3cc25752SFrank Piva     // Round underflow towards negative infinity -> largest negative value
98*3cc25752SFrank Piva     return (sign << 15) | 1;
99*3cc25752SFrank Piva   }
100*3cc25752SFrank Piva 
101*3cc25752SFrank Piva   // Flush to zero
102*3cc25752SFrank Piva   return (sign << 15);
103*3cc25752SFrank Piva }
104*3cc25752SFrank Piva 
105*3cc25752SFrank Piva 
106*3cc25752SFrank Piva /**
107*3cc25752SFrank Piva  * Convert a cl_float to a cl_half.
108*3cc25752SFrank Piva  */
cl_half_from_float(cl_float f,cl_half_rounding_mode rounding_mode)109*3cc25752SFrank Piva static inline cl_half cl_half_from_float(cl_float f, cl_half_rounding_mode rounding_mode)
110*3cc25752SFrank Piva {
111*3cc25752SFrank Piva   // Type-punning to get direct access to underlying bits
112*3cc25752SFrank Piva   union
113*3cc25752SFrank Piva   {
114*3cc25752SFrank Piva     cl_float f;
115*3cc25752SFrank Piva     uint32_t i;
116*3cc25752SFrank Piva   } f32;
117*3cc25752SFrank Piva   f32.f = f;
118*3cc25752SFrank Piva 
119*3cc25752SFrank Piva   // Extract sign bit
120*3cc25752SFrank Piva   uint16_t sign = f32.i >> 31;
121*3cc25752SFrank Piva 
122*3cc25752SFrank Piva   // Extract FP32 exponent and mantissa
123*3cc25752SFrank Piva   uint32_t f_exp = (f32.i >> (CL_FLT_MANT_DIG - 1)) & 0xFF;
124*3cc25752SFrank Piva   uint32_t f_mant = f32.i & ((1 << (CL_FLT_MANT_DIG - 1)) - 1);
125*3cc25752SFrank Piva 
126*3cc25752SFrank Piva   // Remove FP32 exponent bias
127*3cc25752SFrank Piva   int32_t exp = f_exp - CL_FLT_MAX_EXP + 1;
128*3cc25752SFrank Piva 
129*3cc25752SFrank Piva   // Add FP16 exponent bias
130*3cc25752SFrank Piva   uint16_t h_exp = (uint16_t)(exp + CL_HALF_MAX_EXP - 1);
131*3cc25752SFrank Piva 
132*3cc25752SFrank Piva   // Position of the bit that will become the FP16 mantissa LSB
133*3cc25752SFrank Piva   uint32_t lsb_pos = CL_FLT_MANT_DIG - CL_HALF_MANT_DIG;
134*3cc25752SFrank Piva 
135*3cc25752SFrank Piva   // Check for NaN / infinity
136*3cc25752SFrank Piva   if (f_exp == 0xFF)
137*3cc25752SFrank Piva   {
138*3cc25752SFrank Piva     if (f_mant)
139*3cc25752SFrank Piva     {
140*3cc25752SFrank Piva       // NaN -> propagate mantissa and silence it
141*3cc25752SFrank Piva       uint16_t h_mant = (uint16_t)(f_mant >> lsb_pos);
142*3cc25752SFrank Piva       h_mant |= 0x200;
143*3cc25752SFrank Piva       return (sign << 15) | CL_HALF_EXP_MASK | h_mant;
144*3cc25752SFrank Piva     }
145*3cc25752SFrank Piva     else
146*3cc25752SFrank Piva     {
147*3cc25752SFrank Piva       // Infinity -> zero mantissa
148*3cc25752SFrank Piva       return (sign << 15) | CL_HALF_EXP_MASK;
149*3cc25752SFrank Piva     }
150*3cc25752SFrank Piva   }
151*3cc25752SFrank Piva 
152*3cc25752SFrank Piva   // Check for zero
153*3cc25752SFrank Piva   if (!f_exp && !f_mant)
154*3cc25752SFrank Piva   {
155*3cc25752SFrank Piva     return (sign << 15);
156*3cc25752SFrank Piva   }
157*3cc25752SFrank Piva 
158*3cc25752SFrank Piva   // Check for overflow
159*3cc25752SFrank Piva   if (exp >= CL_HALF_MAX_EXP)
160*3cc25752SFrank Piva   {
161*3cc25752SFrank Piva     return cl_half_handle_overflow(rounding_mode, sign);
162*3cc25752SFrank Piva   }
163*3cc25752SFrank Piva 
164*3cc25752SFrank Piva   // Check for underflow
165*3cc25752SFrank Piva   if (exp < (CL_HALF_MIN_EXP - CL_HALF_MANT_DIG - 1))
166*3cc25752SFrank Piva   {
167*3cc25752SFrank Piva     return cl_half_handle_underflow(rounding_mode, sign);
168*3cc25752SFrank Piva   }
169*3cc25752SFrank Piva 
170*3cc25752SFrank Piva   // Check for value that will become denormal
171*3cc25752SFrank Piva   if (exp < -14)
172*3cc25752SFrank Piva   {
173*3cc25752SFrank Piva     // Denormal -> include the implicit 1 from the FP32 mantissa
174*3cc25752SFrank Piva     h_exp = 0;
175*3cc25752SFrank Piva     f_mant |= 1 << (CL_FLT_MANT_DIG - 1);
176*3cc25752SFrank Piva 
177*3cc25752SFrank Piva     // Mantissa shift amount depends on exponent
178*3cc25752SFrank Piva     lsb_pos = -exp + (CL_FLT_MANT_DIG - 25);
179*3cc25752SFrank Piva   }
180*3cc25752SFrank Piva 
181*3cc25752SFrank Piva   // Generate FP16 mantissa by shifting FP32 mantissa
182*3cc25752SFrank Piva   uint16_t h_mant = (uint16_t)(f_mant >> lsb_pos);
183*3cc25752SFrank Piva 
184*3cc25752SFrank Piva   // Check whether we need to round
185*3cc25752SFrank Piva   uint32_t halfway = 1 << (lsb_pos - 1);
186*3cc25752SFrank Piva   uint32_t mask = (halfway << 1) - 1;
187*3cc25752SFrank Piva   switch (rounding_mode)
188*3cc25752SFrank Piva   {
189*3cc25752SFrank Piva     case CL_HALF_RTE:
190*3cc25752SFrank Piva       if ((f_mant & mask) > halfway)
191*3cc25752SFrank Piva       {
192*3cc25752SFrank Piva         // More than halfway -> round up
193*3cc25752SFrank Piva         h_mant += 1;
194*3cc25752SFrank Piva       }
195*3cc25752SFrank Piva       else if ((f_mant & mask) == halfway)
196*3cc25752SFrank Piva       {
197*3cc25752SFrank Piva         // Exactly halfway -> round to nearest even
198*3cc25752SFrank Piva         if (h_mant & 0x1)
199*3cc25752SFrank Piva           h_mant += 1;
200*3cc25752SFrank Piva       }
201*3cc25752SFrank Piva       break;
202*3cc25752SFrank Piva     case CL_HALF_RTZ:
203*3cc25752SFrank Piva       // Mantissa has already been truncated -> do nothing
204*3cc25752SFrank Piva       break;
205*3cc25752SFrank Piva     case CL_HALF_RTP:
206*3cc25752SFrank Piva       if ((f_mant & mask) && !sign)
207*3cc25752SFrank Piva       {
208*3cc25752SFrank Piva         // Round positive numbers up
209*3cc25752SFrank Piva         h_mant += 1;
210*3cc25752SFrank Piva       }
211*3cc25752SFrank Piva       break;
212*3cc25752SFrank Piva     case CL_HALF_RTN:
213*3cc25752SFrank Piva       if ((f_mant & mask) && sign)
214*3cc25752SFrank Piva       {
215*3cc25752SFrank Piva         // Round negative numbers down
216*3cc25752SFrank Piva         h_mant += 1;
217*3cc25752SFrank Piva       }
218*3cc25752SFrank Piva       break;
219*3cc25752SFrank Piva   }
220*3cc25752SFrank Piva 
221*3cc25752SFrank Piva   // Check for mantissa overflow
222*3cc25752SFrank Piva   if (h_mant & 0x400)
223*3cc25752SFrank Piva   {
224*3cc25752SFrank Piva     h_exp += 1;
225*3cc25752SFrank Piva     h_mant = 0;
226*3cc25752SFrank Piva   }
227*3cc25752SFrank Piva 
228*3cc25752SFrank Piva   return (sign << 15) | (h_exp << 10) | h_mant;
229*3cc25752SFrank Piva }
230*3cc25752SFrank Piva 
231*3cc25752SFrank Piva 
232*3cc25752SFrank Piva /**
233*3cc25752SFrank Piva  * Convert a cl_double to a cl_half.
234*3cc25752SFrank Piva  */
cl_half_from_double(cl_double d,cl_half_rounding_mode rounding_mode)235*3cc25752SFrank Piva static inline cl_half cl_half_from_double(cl_double d, cl_half_rounding_mode rounding_mode)
236*3cc25752SFrank Piva {
237*3cc25752SFrank Piva   // Type-punning to get direct access to underlying bits
238*3cc25752SFrank Piva   union
239*3cc25752SFrank Piva   {
240*3cc25752SFrank Piva     cl_double d;
241*3cc25752SFrank Piva     uint64_t i;
242*3cc25752SFrank Piva   } f64;
243*3cc25752SFrank Piva   f64.d = d;
244*3cc25752SFrank Piva 
245*3cc25752SFrank Piva   // Extract sign bit
246*3cc25752SFrank Piva   uint16_t sign = f64.i >> 63;
247*3cc25752SFrank Piva 
248*3cc25752SFrank Piva   // Extract FP64 exponent and mantissa
249*3cc25752SFrank Piva   uint64_t d_exp = (f64.i >> (CL_DBL_MANT_DIG - 1)) & 0x7FF;
250*3cc25752SFrank Piva   uint64_t d_mant = f64.i & (((uint64_t)1 << (CL_DBL_MANT_DIG - 1)) - 1);
251*3cc25752SFrank Piva 
252*3cc25752SFrank Piva   // Remove FP64 exponent bias
253*3cc25752SFrank Piva   int64_t exp = d_exp - CL_DBL_MAX_EXP + 1;
254*3cc25752SFrank Piva 
255*3cc25752SFrank Piva   // Add FP16 exponent bias
256*3cc25752SFrank Piva   uint16_t h_exp = (uint16_t)(exp + CL_HALF_MAX_EXP - 1);
257*3cc25752SFrank Piva 
258*3cc25752SFrank Piva   // Position of the bit that will become the FP16 mantissa LSB
259*3cc25752SFrank Piva   uint32_t lsb_pos = CL_DBL_MANT_DIG - CL_HALF_MANT_DIG;
260*3cc25752SFrank Piva 
261*3cc25752SFrank Piva   // Check for NaN / infinity
262*3cc25752SFrank Piva   if (d_exp == 0x7FF)
263*3cc25752SFrank Piva   {
264*3cc25752SFrank Piva     if (d_mant)
265*3cc25752SFrank Piva     {
266*3cc25752SFrank Piva       // NaN -> propagate mantissa and silence it
267*3cc25752SFrank Piva       uint16_t h_mant = (uint16_t)(d_mant >> lsb_pos);
268*3cc25752SFrank Piva       h_mant |= 0x200;
269*3cc25752SFrank Piva       return (sign << 15) | CL_HALF_EXP_MASK | h_mant;
270*3cc25752SFrank Piva     }
271*3cc25752SFrank Piva     else
272*3cc25752SFrank Piva     {
273*3cc25752SFrank Piva       // Infinity -> zero mantissa
274*3cc25752SFrank Piva       return (sign << 15) | CL_HALF_EXP_MASK;
275*3cc25752SFrank Piva     }
276*3cc25752SFrank Piva   }
277*3cc25752SFrank Piva 
278*3cc25752SFrank Piva   // Check for zero
279*3cc25752SFrank Piva   if (!d_exp && !d_mant)
280*3cc25752SFrank Piva   {
281*3cc25752SFrank Piva     return (sign << 15);
282*3cc25752SFrank Piva   }
283*3cc25752SFrank Piva 
284*3cc25752SFrank Piva   // Check for overflow
285*3cc25752SFrank Piva   if (exp >= CL_HALF_MAX_EXP)
286*3cc25752SFrank Piva   {
287*3cc25752SFrank Piva     return cl_half_handle_overflow(rounding_mode, sign);
288*3cc25752SFrank Piva   }
289*3cc25752SFrank Piva 
290*3cc25752SFrank Piva   // Check for underflow
291*3cc25752SFrank Piva   if (exp < (CL_HALF_MIN_EXP - CL_HALF_MANT_DIG - 1))
292*3cc25752SFrank Piva   {
293*3cc25752SFrank Piva     return cl_half_handle_underflow(rounding_mode, sign);
294*3cc25752SFrank Piva   }
295*3cc25752SFrank Piva 
296*3cc25752SFrank Piva   // Check for value that will become denormal
297*3cc25752SFrank Piva   if (exp < -14)
298*3cc25752SFrank Piva   {
299*3cc25752SFrank Piva     // Include the implicit 1 from the FP64 mantissa
300*3cc25752SFrank Piva     h_exp = 0;
301*3cc25752SFrank Piva     d_mant |= (uint64_t)1 << (CL_DBL_MANT_DIG - 1);
302*3cc25752SFrank Piva 
303*3cc25752SFrank Piva     // Mantissa shift amount depends on exponent
304*3cc25752SFrank Piva     lsb_pos = (uint32_t)(-exp + (CL_DBL_MANT_DIG - 25));
305*3cc25752SFrank Piva   }
306*3cc25752SFrank Piva 
307*3cc25752SFrank Piva   // Generate FP16 mantissa by shifting FP64 mantissa
308*3cc25752SFrank Piva   uint16_t h_mant = (uint16_t)(d_mant >> lsb_pos);
309*3cc25752SFrank Piva 
310*3cc25752SFrank Piva   // Check whether we need to round
311*3cc25752SFrank Piva   uint64_t halfway = (uint64_t)1 << (lsb_pos - 1);
312*3cc25752SFrank Piva   uint64_t mask = (halfway << 1) - 1;
313*3cc25752SFrank Piva   switch (rounding_mode)
314*3cc25752SFrank Piva   {
315*3cc25752SFrank Piva     case CL_HALF_RTE:
316*3cc25752SFrank Piva       if ((d_mant & mask) > halfway)
317*3cc25752SFrank Piva       {
318*3cc25752SFrank Piva         // More than halfway -> round up
319*3cc25752SFrank Piva         h_mant += 1;
320*3cc25752SFrank Piva       }
321*3cc25752SFrank Piva       else if ((d_mant & mask) == halfway)
322*3cc25752SFrank Piva       {
323*3cc25752SFrank Piva         // Exactly halfway -> round to nearest even
324*3cc25752SFrank Piva         if (h_mant & 0x1)
325*3cc25752SFrank Piva           h_mant += 1;
326*3cc25752SFrank Piva       }
327*3cc25752SFrank Piva       break;
328*3cc25752SFrank Piva     case CL_HALF_RTZ:
329*3cc25752SFrank Piva       // Mantissa has already been truncated -> do nothing
330*3cc25752SFrank Piva       break;
331*3cc25752SFrank Piva     case CL_HALF_RTP:
332*3cc25752SFrank Piva       if ((d_mant & mask) && !sign)
333*3cc25752SFrank Piva       {
334*3cc25752SFrank Piva         // Round positive numbers up
335*3cc25752SFrank Piva         h_mant += 1;
336*3cc25752SFrank Piva       }
337*3cc25752SFrank Piva       break;
338*3cc25752SFrank Piva     case CL_HALF_RTN:
339*3cc25752SFrank Piva       if ((d_mant & mask) && sign)
340*3cc25752SFrank Piva       {
341*3cc25752SFrank Piva         // Round negative numbers down
342*3cc25752SFrank Piva         h_mant += 1;
343*3cc25752SFrank Piva       }
344*3cc25752SFrank Piva       break;
345*3cc25752SFrank Piva   }
346*3cc25752SFrank Piva 
347*3cc25752SFrank Piva   // Check for mantissa overflow
348*3cc25752SFrank Piva   if (h_mant & 0x400)
349*3cc25752SFrank Piva   {
350*3cc25752SFrank Piva     h_exp += 1;
351*3cc25752SFrank Piva     h_mant = 0;
352*3cc25752SFrank Piva   }
353*3cc25752SFrank Piva 
354*3cc25752SFrank Piva   return (sign << 15) | (h_exp << 10) | h_mant;
355*3cc25752SFrank Piva }
356*3cc25752SFrank Piva 
357*3cc25752SFrank Piva 
358*3cc25752SFrank Piva /**
359*3cc25752SFrank Piva  * Convert a cl_half to a cl_float.
360*3cc25752SFrank Piva  */
cl_half_to_float(cl_half h)361*3cc25752SFrank Piva static inline cl_float cl_half_to_float(cl_half h)
362*3cc25752SFrank Piva {
363*3cc25752SFrank Piva   // Type-punning to get direct access to underlying bits
364*3cc25752SFrank Piva   union
365*3cc25752SFrank Piva   {
366*3cc25752SFrank Piva     cl_float f;
367*3cc25752SFrank Piva     uint32_t i;
368*3cc25752SFrank Piva   } f32;
369*3cc25752SFrank Piva 
370*3cc25752SFrank Piva   // Extract sign bit
371*3cc25752SFrank Piva   uint16_t sign = h >> 15;
372*3cc25752SFrank Piva 
373*3cc25752SFrank Piva   // Extract FP16 exponent and mantissa
374*3cc25752SFrank Piva   uint16_t h_exp = (h >> (CL_HALF_MANT_DIG - 1)) & 0x1F;
375*3cc25752SFrank Piva   uint16_t h_mant = h & 0x3FF;
376*3cc25752SFrank Piva 
377*3cc25752SFrank Piva   // Remove FP16 exponent bias
378*3cc25752SFrank Piva   int32_t exp = h_exp - CL_HALF_MAX_EXP + 1;
379*3cc25752SFrank Piva 
380*3cc25752SFrank Piva   // Add FP32 exponent bias
381*3cc25752SFrank Piva   uint32_t f_exp = exp + CL_FLT_MAX_EXP - 1;
382*3cc25752SFrank Piva 
383*3cc25752SFrank Piva   // Check for NaN / infinity
384*3cc25752SFrank Piva   if (h_exp == 0x1F)
385*3cc25752SFrank Piva   {
386*3cc25752SFrank Piva     if (h_mant)
387*3cc25752SFrank Piva     {
388*3cc25752SFrank Piva       // NaN -> propagate mantissa and silence it
389*3cc25752SFrank Piva       uint32_t f_mant = h_mant << (CL_FLT_MANT_DIG - CL_HALF_MANT_DIG);
390*3cc25752SFrank Piva       f_mant |= 0x400000;
391*3cc25752SFrank Piva       f32.i = (sign << 31) | 0x7F800000 | f_mant;
392*3cc25752SFrank Piva       return f32.f;
393*3cc25752SFrank Piva     }
394*3cc25752SFrank Piva     else
395*3cc25752SFrank Piva     {
396*3cc25752SFrank Piva       // Infinity -> zero mantissa
397*3cc25752SFrank Piva       f32.i = (sign << 31) | 0x7F800000;
398*3cc25752SFrank Piva       return f32.f;
399*3cc25752SFrank Piva     }
400*3cc25752SFrank Piva   }
401*3cc25752SFrank Piva 
402*3cc25752SFrank Piva   // Check for zero / denormal
403*3cc25752SFrank Piva   if (h_exp == 0)
404*3cc25752SFrank Piva   {
405*3cc25752SFrank Piva     if (h_mant == 0)
406*3cc25752SFrank Piva     {
407*3cc25752SFrank Piva       // Zero -> zero exponent
408*3cc25752SFrank Piva       f_exp = 0;
409*3cc25752SFrank Piva     }
410*3cc25752SFrank Piva     else
411*3cc25752SFrank Piva     {
412*3cc25752SFrank Piva       // Denormal -> normalize it
413*3cc25752SFrank Piva       // - Shift mantissa to make most-significant 1 implicit
414*3cc25752SFrank Piva       // - Adjust exponent accordingly
415*3cc25752SFrank Piva       uint32_t shift = 0;
416*3cc25752SFrank Piva       while ((h_mant & 0x400) == 0)
417*3cc25752SFrank Piva       {
418*3cc25752SFrank Piva         h_mant <<= 1;
419*3cc25752SFrank Piva         shift++;
420*3cc25752SFrank Piva       }
421*3cc25752SFrank Piva       h_mant &= 0x3FF;
422*3cc25752SFrank Piva       f_exp -= shift - 1;
423*3cc25752SFrank Piva     }
424*3cc25752SFrank Piva   }
425*3cc25752SFrank Piva 
426*3cc25752SFrank Piva   f32.i = (sign << 31) | (f_exp << 23) | (h_mant << 13);
427*3cc25752SFrank Piva   return f32.f;
428*3cc25752SFrank Piva }
429*3cc25752SFrank Piva 
430*3cc25752SFrank Piva 
431*3cc25752SFrank Piva #undef CL_HALF_EXP_MASK
432*3cc25752SFrank Piva #undef CL_HALF_MAX_FINITE_MAG
433*3cc25752SFrank Piva 
434*3cc25752SFrank Piva 
435*3cc25752SFrank Piva #ifdef __cplusplus
436*3cc25752SFrank Piva }
437*3cc25752SFrank Piva #endif
438*3cc25752SFrank Piva 
439*3cc25752SFrank Piva 
440*3cc25752SFrank Piva #endif  /* OPENCL_CL_HALF_H */
441