xref: /aosp_15_r20/external/mesa3d/src/amd/vpelib/src/utils/custom_fp16.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /* Copyright 2022 Advanced Micro Devices, Inc.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a
4  * copy of this software and associated documentation files (the "Software"),
5  * to deal in the Software without restriction, including without limitation
6  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7  * and/or sell copies of the Software, and to permit persons to whom the
8  * Software is furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
16  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19  * OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Authors: AMD
22  *
23  */
24 
25 #include "vpe_assert.h"
26 #include "custom_fp16.h"
27 #include <math.h>
28 #include <stdbool.h>
29 
build_custom_float(double value,const struct vpe_custom_float_format2 * fmt,bool * pbNegative,unsigned int * pexponent,unsigned int * pmantissa)30 static bool build_custom_float(double value, const struct vpe_custom_float_format2 *fmt,
31     bool *pbNegative, unsigned int *pexponent, unsigned int *pmantissa)
32 {
33     bool         bRet             = false;
34     double       mantissaConstant = 1.0;
35     double       base             = 2.0;
36     int          expOffset        = (int)(pow(2.0, fmt->exponentaBits - 1) - 1);
37     double       maxFraction      = 1.0 - pow(0.5, fmt->mantissaBits);
38     unsigned int exponent;
39     double       mantissa;
40     unsigned int Mantissa;
41     int          i;
42     bool         bAlwaysFalse = false;
43 
44     // if value negative and we should consider this otherwize just ignore
45     if (value < 0 && fmt->flags.bits.sign == 1)
46         *pbNegative = true;
47     else
48         *pbNegative = false;
49 
50     do {
51 
52         if (value == 0.0) {
53             *pexponent = 0;
54             *pmantissa = 0;
55             bRet       = true;
56             break;
57         }
58 
59         if (value < 0)
60             value = (-1.0) * value;
61 
62         if (value < mantissaConstant) {
63             /*if log works faster then remove the loops!*/
64             for (i = 1;; i++) {
65                 value *= base;
66                 if (value >= mantissaConstant)
67                     break;
68             }
69             if (expOffset <= i) {
70                 *pexponent = 0;
71                 *pmantissa = 0;
72                 bRet       = true;
73                 break;
74             }
75             exponent = (unsigned int)(expOffset - i);
76         } else if (value >= mantissaConstant + maxFraction) {
77             for (i = 1;; i++) {
78                 value /= base;
79                 if (value <= mantissaConstant + maxFraction)
80                     break;
81             }
82             exponent = (unsigned int)(expOffset + i);
83         } else
84             exponent = (unsigned int)expOffset;
85 
86         mantissa = value - mantissaConstant;
87 
88         if (mantissa < 0.0 || mantissa > 1.0)
89             mantissa = 0;
90         else
91             mantissa *= pow(2.0, fmt->mantissaBits);
92 
93         Mantissa = (unsigned int)mantissa;
94 
95         *pexponent = exponent;
96         *pmantissa = Mantissa;
97 
98         bRet = true;
99 
100     } while (bAlwaysFalse);
101 
102     return bRet;
103 }
104 
setup_custom_float(const struct vpe_custom_float_format2 * fmt,bool bNegative,unsigned int exponent,unsigned int mantissa,uint16_t * pvalue)105 static bool setup_custom_float(const struct vpe_custom_float_format2 *fmt, bool bNegative,
106     unsigned int exponent, unsigned int mantissa, uint16_t *pvalue)
107 {
108     unsigned int value = 0;
109     unsigned int mask;
110     unsigned int i;
111     unsigned int j;
112 
113     if (fmt->exponentaBits == 6 && fmt->mantissaBits == 12 && fmt->flags.bits.sign == 0) {
114         if (exponent & ~(unsigned int)0x3F)
115             exponent = 0x3F;
116         if (mantissa & ~(unsigned int)0xFFF)
117             mantissa = 0xFFF;
118     } else if (fmt->exponentaBits == 6 && fmt->mantissaBits == 10 && fmt->flags.bits.sign == 0) {
119         if (exponent & ~(unsigned int)0x3F)
120             exponent = 0x3F;
121         if (mantissa & ~(unsigned int)0x3FF)
122             mantissa = 0x3FF;
123     } else if (fmt->exponentaBits == 6 && fmt->mantissaBits == 12 && fmt->flags.bits.sign == 1) {
124         if (exponent & ~(unsigned int)0x3F)
125             exponent = 0x3F;
126         if (mantissa & ~(unsigned int)0xFFF)
127             mantissa = 0xFFF;
128     } else if (fmt->exponentaBits == 5 && fmt->mantissaBits == 10 && fmt->flags.bits.sign == 1) {
129         if (exponent & ~(unsigned int)0x1F)
130             exponent = 0x1F;
131         if (mantissa & ~(unsigned int)0x3FF)
132             mantissa = 0x3FF;
133     } else
134         return false;
135 
136     for (i = 0; i < fmt->mantissaBits; i++) {
137         mask = 1 << i;
138 
139         if (mantissa & mask)
140             value |= mask;
141     }
142     for (j = 0; j < fmt->exponentaBits; j++) {
143         mask = 1 << j;
144 
145         if (exponent & mask)
146             value |= mask << i;
147     }
148 
149     if (bNegative == true && fmt->flags.bits.sign == 1)
150         value |= 1 << (i + j);
151 
152     *pvalue = (uint16_t)value;
153 
154     return true;
155 }
156 
vpe_convert_from_float_to_custom_float(double value,const struct vpe_custom_float_format2 * fmt,uint16_t * pvalue)157 bool vpe_convert_from_float_to_custom_float(
158     double value, const struct vpe_custom_float_format2 *fmt, uint16_t *pvalue)
159 {
160     bool         isNegative;
161     unsigned int exponent;
162     unsigned int mantissa;
163     bool         ret = false;
164 
165     VPE_ASSERT(
166         (fmt->flags.bits.sign == 1) && (fmt->mantissaBits == 10) && (fmt->exponentaBits == 5));
167 
168     if (!build_custom_float(value, fmt, &isNegative, &exponent, &mantissa))
169         goto release;
170     if (!setup_custom_float(fmt, isNegative, exponent, mantissa, pvalue))
171         goto release;
172     ret = true;
173 release:
174     return ret;
175 }
176 
setup_custom_float_generic(const struct vpe_custom_float_format2 * fmt,bool bNegative,unsigned int exponent,unsigned int mantissa,int * pvalue)177 static bool setup_custom_float_generic(const struct vpe_custom_float_format2 *fmt, bool bNegative,
178     unsigned int exponent, unsigned int mantissa, int *pvalue)
179 {
180     unsigned int value = 0;
181 
182     int mask;
183 
184     if (fmt->exponentaBits == 6 && fmt->mantissaBits == 12 && fmt->flags.bits.sign == 0) {
185         if (exponent & ~0x3F)
186             exponent = 0x3F;
187         if (mantissa & ~0xFFF)
188             mantissa = 0xFFF;
189     } else if (fmt->exponentaBits == 6 && fmt->mantissaBits == 10 && fmt->flags.bits.sign == 0) {
190         if (exponent & ~0x3F)
191             exponent = 0x3F;
192         if (mantissa & ~0x3FF)
193             mantissa = 0x3FF;
194 
195     } else if (fmt->exponentaBits == 6 && fmt->mantissaBits == 12 && fmt->flags.bits.sign == 1) {
196         if (exponent & ~0x3F)
197             exponent = 0x3F;
198         if (mantissa & ~0xFFF)
199             mantissa = 0xFFF;
200 
201     } else
202         return false;
203 
204     unsigned int i;
205     unsigned int j;
206 
207     for (i = 0; i < fmt->mantissaBits; i++) {
208         mask = 1 << i;
209 
210         if (mantissa & mask)
211             value |= mask;
212     }
213     for (j = 0; j < fmt->exponentaBits; j++) {
214         mask = 1 << j;
215 
216         if (exponent & mask)
217             value |= mask << i;
218     }
219 
220     if (bNegative == true && fmt->flags.bits.sign == 1)
221         value |= 1 << (i + j);
222 
223     *pvalue = value;
224 
225     return true;
226 }
227 
vpe_convert_to_custom_float_generic(double value,const struct vpe_custom_float_format2 * fmt,int * pvalue)228 bool vpe_convert_to_custom_float_generic(
229     double value, const struct vpe_custom_float_format2 *fmt, int *pvalue)
230 {
231     bool         isNegative;
232     unsigned int exponent;
233     unsigned int mantissa;
234 
235     bool ret = false;
236 
237     if (!build_custom_float(value, fmt, &isNegative, &exponent, &mantissa))
238         goto release;
239     if (!setup_custom_float_generic(fmt, isNegative, exponent, mantissa, pvalue))
240         goto release;
241     ret = true;
242 release:
243     return ret;
244 }
245 
vpe_convert_to_custom_float_ex_generic(double value,const struct vpe_custom_float_format2 * fmt,struct vpe_custom_float_value2 * pvalue)246 bool vpe_convert_to_custom_float_ex_generic(double value,
247     const struct vpe_custom_float_format2 *fmt, struct vpe_custom_float_value2 *pvalue)
248 {
249     bool ret = false;
250 
251     if (!build_custom_float(value, fmt, &pvalue->isNegative, &pvalue->exponenta, &pvalue->mantissa))
252         goto release;
253     if (!setup_custom_float_generic(
254             fmt, pvalue->isNegative, pvalue->exponenta, pvalue->mantissa, &pvalue->value))
255         goto release;
256 
257     ret = true;
258 release:
259     return ret;
260 }
261 
vpe_from_1_6_12_to_double(bool bIsNegative,unsigned int E,unsigned int F,double * DoubleFloat)262 bool vpe_from_1_6_12_to_double(
263     bool bIsNegative, unsigned int E, unsigned int F, double *DoubleFloat)
264 {
265     double ret = 0;
266 
267     double M, F1, A, B, C, D2, e12;
268 
269     A   = 2.0;
270     B   = 31.0;
271     C   = 1.0;
272     D2  = -30.0;
273     e12 = pow(2, 12);
274 
275     M = F / e12;
276 
277     if (bIsNegative == false)
278         F1 = 1.0;
279     else
280         F1 = -1.0;
281 
282     if (E > 0 && E < 63)
283         ret = F1 * (C + M) * pow(A, E - B);
284     else if (E == 0 && F != 0)
285         ret = F1 * M * pow(A, D2);
286     else if (E == 0 && F == 0 && bIsNegative == true)
287         ret = -0;
288     else if (E == 0 && F == 0 && bIsNegative == false)
289         ret = 0;
290     else if (E == 63 && F != 0)
291         return false; // -1; /* Not a number*/
292     else if (E == 63 && F == 0 && bIsNegative == true)
293         return false; //-2; /* -Infinity*/
294     else if (E == 63 && F == 0 && bIsNegative == false)
295         return false; // -3; /* Infinity	*/
296 
297     *DoubleFloat = ret;
298 
299     return true;
300 }
301 
vpe_convert_from_float_to_fp16(double value,uint16_t * pvalue)302 bool vpe_convert_from_float_to_fp16(double value, uint16_t *pvalue)
303 {
304     struct vpe_custom_float_format2 fmt;
305 
306     fmt.flags.Uint      = 0;
307     fmt.flags.bits.sign = 1;
308     fmt.mantissaBits    = 10;
309     fmt.exponentaBits   = 5;
310 
311     return vpe_convert_from_float_to_custom_float(value, &fmt, pvalue);
312 }
313