@@@ fltfmt mess
[mLib] / utils / fltfmt-convert.c
1 /* -*-c-*-
2 *
3 * Floating-point format conversions
4 *
5 * (c) 2024 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the mLib utilities library.
11 *
12 * mLib is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU Library General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
16 *
17 * mLib is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
20 * License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib. If not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25 * USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include "config.h"
31
32 #include "bits.h"
33 #include "fltfmt.h"
34
35 /*----- Main code ---------------------------------------------------------*/
36
37 /* Macro machinery. */
38
39 #define CONVERSIONS(_) \
40 _(float, flt, f32) \
41 _(double, dbl, f64)
42
43 #define CONV_DECLS_flt_f32 uint32 t
44 #if (FLT_FORMAT&(FLTFMT_ORGMASK | FLTFMT_TYPEMASK)) == FLTFMT_IEEE_F32
45 # if (FLT_FORMAT&FLTFMT_ENDMASK) == FLTFMT_BE
46 # define CONV_LOAD_flt_f32 do { t = LOAD32_B(&x); } while (0)
47 # define CONV_STORE_flt_f32 do { STORE32_B(z_out, t); } while (0)
48 # elif (FLT_FORMAT&FLTFMT_ENDMASK) == FLTFMT_LE
49 # define CONV_LOAD_flt_f32 do { t = LOAD32_L(&x); } while (0)
50 # define CONV_STORE_flt_f32 do { STORE32_L(z_out, t); } while (0)
51 # else
52 # error "unimplemented byte order"
53 # endif
54 # ifdef FLTFMT__MUST_FROB_NANS
55 # define CONV_FROB_flt_f32 do { FLTFMT__FROB_NAN_F32(&t, rc); } while (0)
56 # else
57 # define CONV_FROB_flt_f32 do ; while (0)
58 # endif
59 #else
60 # define CONV_LOAD_flt_f32 do { \
61 struct floatbits u = FLOATBITS_INIT; \
62 rc |= fltfmt_decflt(&u, x, r); \
63 rc |= fltfmt_encieee(&fltfmt_f32, &t, &u, r, FLTERR_ALLERRS); \
64 fltfmt_freebits(&u); \
65 } while (0)
66 # define CONV_STORE_flt_f32 do { \
67 struct floatbits u = FLOATBITS_INIT; \
68 rc |= fltfmt_decieee(&fltfmt_f32, &u, &t); \
69 rc |= fltfmt_encflt(z_out, &u, r); \
70 fltfmt_freebits(&u); \
71 } while (0)
72 # define CONV_FROB_flt_f32 do ; while (0)
73 #endif
74 #define CONV_LOADB_flt_f32 do { t = LOAD32_B(p); } while (0)
75 #define CONV_LOADL_flt_f32 do { t = LOAD32_L(p); } while (0)
76 #define CONV_STOREB_flt_f32 do { STORE32_B(p, t); } while (0)
77 #define CONV_STOREL_flt_f32 do { STORE32_L(p, t); } while (0)
78
79 #define CONV_DECLS_dbl_f64 kludge64 t
80 #if (DBL_FORMAT&(FLTFMT_ORGMASK | FLTFMT_TYPEMASK)) == FLTFMT_IEEE_F64
81 # if (DBL_FORMAT&FLTFMT_ENDMASK) == FLTFMT_BE
82 # define CONV_LOAD_dbl_f64 do { LOAD64_B_(t, &x); } while (0)
83 # define CONV_STORE_dbl_f64 do { STORE64_B_(z_out, t); } while (0)
84 # elif (DBL_FORMAT&FLTFMT_ENDMASK) == FLTFMT_LE
85 # define CONV_LOAD_dbl_f64 do { LOAD64_L_(t, &x); } while (0)
86 # define CONV_STORE_dbl_f64 do { STORE64_L_(z_out, t); } while (0)
87 # else
88 # error "unimplemented byte order"
89 # endif
90 # ifdef FLTFMT__MUST_FROB_NANS
91 # define CONV_FROB_dbl_f64 do { \
92 uint32 u[2]; \
93 u[0] = HI64(t); u[1] = LO64(t); \
94 FLTFMT__FROB_NAN_F64(&u, rc); \
95 SET64(t, u[0], u[1]); \
96 } while (0)
97 # else
98 # define CONV_FROB_dbl_f64 do ; while (0)
99 # endif
100 #else
101 # define CONV_LOAD_dbl_f64 do { \
102 struct floatbits u = FLOATBITS_INIT; uint32 v[2]; \
103 rc |= fltfmt_decdbl(&u, x, r); \
104 rc |= fltfmt_encieee(&fltfmt_f64, v, &u, r, FLTERR_ALLERRS); \
105 SET64(t, v[0], v[1]); fltfmt_freebits(&u); \
106 } while (0)
107 # define CONV_STORE_dbl_f64 do { \
108 struct floatbits u = FLOATBITS_INIT; uint32 v[2]; \
109 v[0] = HI64(t); v[1] = LO64(t); \
110 rc |= fltfmt_decieee(&fltfmt_f64, &u, v); \
111 rc |= fltfmt_encdbl(z_out, &u, r); \
112 fltfmt_freebits(&u); \
113 } while (0)
114 # define CONV_FROB_dbl_f64 do ; while (0)
115 #endif
116 #define CONV_LOADB_dbl_f64 do { LOAD64_B_(t, p); } while (0)
117 #define CONV_LOADL_dbl_f64 do { LOAD64_L_(t, p); } while (0)
118 #define CONV_STOREB_dbl_f64 do { STORE64_B_(p, t); } while (0)
119 #define CONV_STOREL_dbl_f64 do { STORE64_L_(p, t); } while (0)
120
121 /* --- @fltfmt_CTYtoFTYE@ --- *
122 *
123 * Arguments: @octet *p@ = output pointer
124 * @float x@, @double x@ = value to convert
125 * @unsigned r@ = rounding mode
126 *
127 * Returns: Error flags (@FLTERR_...@).
128 *
129 * Use: Encode a native C floating-point value in an external format.
130 *
131 * The @CTY@ is an abbreviation for a C type: @flt@ for @float@,
132 * or @dbl@ for @double@; @fty@ is an abbreviation for the
133 * external format, @f32@ for IEEE Binary32, or @f64@ for IEEE
134 * Binary64; and @E@ is @l@ for little-endian or @b@ for
135 * big-endian byte order. Not all combinations are currently
136 * supported.
137 *
138 * On platforms where the external format is used natively,
139 * these functions are simple data copies.
140 */
141
142 #define DEF_CONV(ctype, cty, fty) \
143 unsigned fltfmt_##cty##to##fty##l(octet *p, ctype x, unsigned r) \
144 { \
145 unsigned rc = 0; CONV_DECLS_##cty##_##fty; \
146 \
147 CONV_LOAD_##cty##_##fty; \
148 CONV_FROB_##cty##_##fty; \
149 CONV_STOREL_##cty##_##fty; \
150 return (rc); \
151 } \
152 \
153 unsigned fltfmt_##cty##to##fty##b(octet *p, ctype x, unsigned r) \
154 { \
155 unsigned rc = 0; CONV_DECLS_##cty##_##fty; \
156 \
157 CONV_LOAD_##cty##_##fty; \
158 CONV_FROB_##cty##_##fty; \
159 CONV_STOREB_##cty##_##fty; \
160 return (rc); \
161 }
162
163 CONVERSIONS(DEF_CONV)
164
165 #undef DEF_CONV
166
167 /* --- @fltfmt_FTYEtoCTY@ --- *
168 *
169 * Arguments: @float *z_out@, @double *z_out@ = storage for output
170 * @const octet *p@ = input pointer
171 * @unsigned r@ = rounding mode
172 *
173 * Returns: Error flags (@FLTERR_...@).
174 *
175 * Use: Decodes a floating point value in an external format into a
176 * native value.
177 *
178 * The naming conventions are the same as for @fltfmt_dbltof64b@
179 * above.
180 *
181 * On platforms where the external format is used natively,
182 * these functions are simple data copies.
183 */
184
185 #define DEF_CONV(ctype, cty, fty) \
186 unsigned fltfmt_##fty##lto##cty(ctype *z_out, const octet *p, unsigned r) \
187 { \
188 unsigned rc = 0; CONV_DECLS_##cty##_##fty; \
189 \
190 CONV_LOADL_##cty##_##fty; \
191 CONV_FROB_##cty##_##fty; \
192 CONV_STORE_##cty##_##fty; \
193 return (rc); \
194 } \
195 \
196 unsigned fltfmt_##fty##bto##cty(ctype *z_out, const octet *p, unsigned r) \
197 { \
198 unsigned rc = 0; CONV_DECLS_##cty##_##fty; \
199 \
200 CONV_LOADB_##cty##_##fty; \
201 CONV_FROB_##cty##_##fty; \
202 CONV_STORE_##cty##_##fty; \
203 return (rc); \
204 }
205
206 CONVERSIONS(DEF_CONV)
207
208 #undef DEF_CONV
209
210 /*----- That's all, folks -------------------------------------------------*/