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