Add LICENSE
[riscv-tests.git] / benchmarks / vec-fft / cvt16.c
1 // See LICENSE for license details.
2
3 #include "cvt16.h"
4
5 #define H_BIAS (UINT16_C(0xf))
6 #define H_F_MASK (UINT16_C(0x03FF))
7 #define H_E_MASK (UINT16_C(0x7C00))
8 #define H_E_SHIFT (10)
9 #define H_S_MASK (UINT16_C(0x8000))
10
11 #define H_QNAN (H_F_MASK)
12
13 #define S_BIAS (UINT32_C(0x7F))
14 #define S_F_MASK (UINT32_C(0x007fffff))
15 #define S_E_MASK (UINT32_C(0x7f800000))
16 #define S_E_SHIFT (23)
17 #define S_S_MASK (UINT32_C(0x80000000))
18
19 #define S_QNAN (S_F_MASK)
20
21 #define PAD (S_E_SHIFT - H_E_SHIFT)
22
23 uint_fast32_t cvt_hs(uint_fast16_t x)
24 {
25 #define MSB (UINT32_C(0x00800000))
26 uint_fast32_t frac, exp, sign;
27 frac = (x & H_F_MASK) << PAD;
28 exp = (x & H_E_MASK);
29 sign = (x & H_S_MASK);
30
31 switch (exp) {
32 case 0:
33 if (frac) { /* Denormal */
34 exp = S_BIAS - 14;
35 /* Adjust fraction for implicit leading 1-bit */
36 for (; !(frac & MSB); frac <<= 1, exp--);
37 frac &= ~(MSB);
38 exp <<= S_E_SHIFT;
39 }
40 break;
41
42 case H_E_MASK: /* Infinity and NaN */
43 exp = S_E_MASK;
44 if (frac) { /* Set padding bits for NaN */
45 frac |= (1 << PAD) - 1;
46 }
47 break;
48 default:
49 exp += (S_BIAS - H_BIAS) << H_E_SHIFT; /* Re-bias */
50 exp <<= PAD;
51 }
52 return (sign << 16) | exp | frac;
53 #undef MSB
54 }
55
56 /*
57 * LSB : frac[13]
58 * Guard bit (G): frac[12]
59 * Round bit (R): frac[11]
60 * Sticky bit (S): OR of frac[10..0]
61 *
62 * RTZ:
63 * truncate
64 * RUP:
65 * 000 : exact
66 * else : round up
67 * RDN:
68 * 000 : exact
69 * else : round down
70 * RNE:
71 * 0xx : round down
72 * 100 : tie; round up if LSB is 1
73 * 101 : round up
74 * 110 : round up
75 * 111 : round up
76 */
77 uint_fast16_t cvt_sh(uint_fast32_t x, int rm)
78 {
79 #define MSB UINT16_C(0x0400)
80 uint_fast32_t frac, exp, sign;
81 int e;
82 sign = (x & S_S_MASK) >> 16;
83 exp = (x & S_E_MASK);
84 if (exp && exp != S_E_MASK) {
85 int inc;
86 inc = 0;
87 switch (rm) {
88 case RNE:
89 /* Round up if G is set and either R, S,
90 or the bit before G is non-zero */
91 inc = (x & 0x1000) && (x & 0x2fff);
92 break;
93 case RUP:
94 inc = ((x & 0x1fff) != 0) && (!sign);
95 break;
96 case RDN:
97 inc = ((x & 0x1fff) != 0) && sign;
98 break;
99 }
100 x += inc << PAD;
101 exp = (x & S_E_MASK);
102 }
103 frac = (x & S_F_MASK) >> PAD;
104
105 e = (exp >> S_E_SHIFT) - S_BIAS;
106 if (e < -24) { /* Round to zero */
107 return sign;
108 } else if (e < -14) { /* Denormal */
109 frac = (frac | MSB) >> (-e - 14);
110 return sign | frac;
111 } else if (e < 16) {
112 exp = (e + H_BIAS) << H_E_SHIFT;
113 } else if (e < 127) { /* Round to infinity */
114 exp = H_E_MASK;
115 frac = 0;
116 } else {
117 /* Infinity and NaN */
118 }
119 return sign | exp | frac;
120 #undef MSB
121 }
122