aboutsummaryrefslogtreecommitdiff
path: root/benchmarks/vec-fft/cvt16.c
blob: 4307c7db62ba8aec67b6b761f42afe6fe086cf2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "cvt16.h"

#define H_BIAS    (UINT16_C(0xf))
#define H_F_MASK  (UINT16_C(0x03FF))
#define H_E_MASK  (UINT16_C(0x7C00))
#define H_E_SHIFT (10)
#define H_S_MASK  (UINT16_C(0x8000))

#define H_QNAN    (H_F_MASK)

#define S_BIAS    (UINT32_C(0x7F))
#define S_F_MASK  (UINT32_C(0x007fffff))
#define S_E_MASK  (UINT32_C(0x7f800000))
#define S_E_SHIFT (23)
#define S_S_MASK  (UINT32_C(0x80000000))

#define S_QNAN    (S_F_MASK)

#define PAD  (S_E_SHIFT - H_E_SHIFT)

uint_fast32_t cvt_hs(uint_fast16_t x)
{
#define MSB (UINT32_C(0x00800000))
	uint_fast32_t frac, exp, sign;
	frac = (x & H_F_MASK) << PAD;
	exp  = (x & H_E_MASK);
	sign = (x & H_S_MASK);

	switch (exp) {
	case 0:
		if (frac) { /* Denormal */
			exp = S_BIAS - 14;
			/* Adjust fraction for implicit leading 1-bit */
			for (; !(frac & MSB); frac <<= 1, exp--);
			frac &= ~(MSB);
			exp <<= S_E_SHIFT;
		}
		break;

	case H_E_MASK: /* Infinity and NaN */
		exp = S_E_MASK;
		if (frac) { /* Set padding bits for NaN */
			frac |= (1 << PAD) - 1;
		}
		break;
	default:
		exp += (S_BIAS - H_BIAS) << H_E_SHIFT; /* Re-bias */
		exp <<= PAD;
	}
	return (sign << 16) | exp | frac;
#undef MSB
}

/*
 * LSB           : frac[13]
 * Guard bit  (G): frac[12]
 * Round bit  (R): frac[11]
 * Sticky bit (S): OR of frac[10..0]
 *
 * RTZ:
 *   truncate
 * RUP:
 *   000 : exact
 *  else : round up
 * RDN:
 *   000 : exact
 *  else : round down
 * RNE:
 *   0xx : round down 
 *   100 : tie; round up if LSB is 1
 *   101 : round up
 *   110 : round up
 *   111 : round up
 */
uint_fast16_t cvt_sh(uint_fast32_t x, int rm)
{
#define MSB UINT16_C(0x0400)
	uint_fast32_t frac, exp, sign;
	int e;
	sign = (x & S_S_MASK) >> 16;
	exp = (x & S_E_MASK);
	if (exp && exp != S_E_MASK) {
		int inc;
		inc = 0;
		switch (rm) {
		case RNE:
			/* Round up if G is set and either R, S,
			   or the bit before G is non-zero */
			inc = (x & 0x1000) && (x & 0x2fff);
			break;
		case RUP:
			inc = ((x & 0x1fff) != 0) && (!sign);
			break;
		case RDN:
			inc = ((x & 0x1fff) != 0) && sign;
			break;
		}
		x += inc << PAD;
		exp = (x & S_E_MASK);
	}
	frac = (x & S_F_MASK) >> PAD;

	e = (exp >> S_E_SHIFT) - S_BIAS;
	if (e < -24) { /* Round to zero */
		return sign;
	} else if (e < -14) { /* Denormal */
		frac = (frac | MSB) >> (-e - 14);
		return sign | frac;
	} else if (e < 16) {
		exp = (e + H_BIAS) << H_E_SHIFT;
	} else if (e < 127) { /* Round to infinity */
		exp = H_E_MASK;
		frac = 0;
	} else {
		/* Infinity and NaN */
	}
	return sign | exp | frac;
#undef MSB
}