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