@@@ fltfmt wip
[mLib] / utils / fltfmt-convert.c
CommitLineData
b1a20bee
MW
1/* -*-c-*-
2 *
dc6eea4e 3 * Direct floating-point format conversions
b1a20bee
MW
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
dc6eea4e
MW
43#if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
44# define FROB_NANS
45#endif
46
b1a20bee
MW
47#define CONV_DECLS_flt_f32 uint32 t
48#if (FLT_FORMAT&(FLTFMT_ORGMASK | FLTFMT_TYPEMASK)) == FLTFMT_IEEE_F32
49# if (FLT_FORMAT&FLTFMT_ENDMASK) == FLTFMT_BE
50# define CONV_LOAD_flt_f32 do { t = LOAD32_B(&x); } while (0)
51# define CONV_STORE_flt_f32 do { STORE32_B(z_out, t); } while (0)
52# elif (FLT_FORMAT&FLTFMT_ENDMASK) == FLTFMT_LE
53# define CONV_LOAD_flt_f32 do { t = LOAD32_L(&x); } while (0)
54# define CONV_STORE_flt_f32 do { STORE32_L(z_out, t); } while (0)
55# else
56# error "unimplemented byte order"
57# endif
dc6eea4e
MW
58# ifdef FROB_NANS
59# define CONV_FROBNANflt_f32 do { \
60 if ((t&0x7f800000) != 0x7f800000 || !(t&0x007fffff)) \
61 ; \
62 else if (t&0x003fffff) \
63 t ^= 0x00400000; \
64 else { \
65 t = (t&0x80000000) | 0x00000001; \
66 rc |= FLTERR_INEXACT; \
67 } \
68 } while (0)
b1a20bee 69# else
dc6eea4e 70# define CONV_FROBNANflt_f32 do ; while (0)
b1a20bee
MW
71# endif
72#else
73# define CONV_LOAD_flt_f32 do { \
74 struct floatbits u = FLOATBITS_INIT; \
75 rc |= fltfmt_decflt(&u, x, r); \
76 rc |= fltfmt_encieee(&fltfmt_f32, &t, &u, r, FLTERR_ALLERRS); \
77 fltfmt_freebits(&u); \
78 } while (0)
79# define CONV_STORE_flt_f32 do { \
80 struct floatbits u = FLOATBITS_INIT; \
81 rc |= fltfmt_decieee(&fltfmt_f32, &u, &t); \
82 rc |= fltfmt_encflt(z_out, &u, r); \
83 fltfmt_freebits(&u); \
84 } while (0)
dc6eea4e 85# define CONV_FROBNANflt_f32 do ; while (0)
b1a20bee
MW
86#endif
87#define CONV_LOADB_flt_f32 do { t = LOAD32_B(p); } while (0)
88#define CONV_LOADL_flt_f32 do { t = LOAD32_L(p); } while (0)
89#define CONV_STOREB_flt_f32 do { STORE32_B(p, t); } while (0)
90#define CONV_STOREL_flt_f32 do { STORE32_L(p, t); } while (0)
91
92#define CONV_DECLS_dbl_f64 kludge64 t
93#if (DBL_FORMAT&(FLTFMT_ORGMASK | FLTFMT_TYPEMASK)) == FLTFMT_IEEE_F64
94# if (DBL_FORMAT&FLTFMT_ENDMASK) == FLTFMT_BE
95# define CONV_LOAD_dbl_f64 do { LOAD64_B_(t, &x); } while (0)
96# define CONV_STORE_dbl_f64 do { STORE64_B_(z_out, t); } while (0)
97# elif (DBL_FORMAT&FLTFMT_ENDMASK) == FLTFMT_LE
98# define CONV_LOAD_dbl_f64 do { LOAD64_L_(t, &x); } while (0)
99# define CONV_STORE_dbl_f64 do { STORE64_L_(z_out, t); } while (0)
100# else
101# error "unimplemented byte order"
102# endif
dc6eea4e
MW
103# ifdef FROB_NANS
104# define CONV_FROBNANdbl_f64 do { \
105 kludge64 u, v; \
106 SET64(u, 0x7ff00000, 0x00000000); AND64(v, t, u); \
107 if (CMP64(v, ==, u)) { \
108 SET64(u, 0x000fffff, 0xffffffff); AND64(v, t, u); \
109 if (!ZERO64(v)) { \
110 SET64(u, 0x0007ffff, 0xffffffff); AND64(v, t, u); \
111 if (!ZERO64(v)) \
112 { SET64(u, 0x00080000, 0x00000000); XOR64(t, t, u); } \
113 else { \
114 SET64(u, 0x80000000, 0x00000000); AND64(t, t, u); \
115 SET64(u, 0x00000000, 0x00000001); OR64(t, t, u); \
116 rc |= FLTERR_INEXACT; \
117 } \
118 } \
119 } \
b1a20bee
MW
120 } while (0)
121# else
dc6eea4e 122# define CONV_FROBNANdbl_f64 do ; while (0)
b1a20bee
MW
123# endif
124#else
125# define CONV_LOAD_dbl_f64 do { \
126 struct floatbits u = FLOATBITS_INIT; uint32 v[2]; \
127 rc |= fltfmt_decdbl(&u, x, r); \
128 rc |= fltfmt_encieee(&fltfmt_f64, v, &u, r, FLTERR_ALLERRS); \
129 SET64(t, v[0], v[1]); fltfmt_freebits(&u); \
130 } while (0)
131# define CONV_STORE_dbl_f64 do { \
132 struct floatbits u = FLOATBITS_INIT; uint32 v[2]; \
133 v[0] = HI64(t); v[1] = LO64(t); \
134 rc |= fltfmt_decieee(&fltfmt_f64, &u, v); \
135 rc |= fltfmt_encdbl(z_out, &u, r); \
136 fltfmt_freebits(&u); \
137 } while (0)
dc6eea4e 138# define CONV_FROBNANdbl_f64 do ; while (0)
b1a20bee
MW
139#endif
140#define CONV_LOADB_dbl_f64 do { LOAD64_B_(t, p); } while (0)
141#define CONV_LOADL_dbl_f64 do { LOAD64_L_(t, p); } while (0)
142#define CONV_STOREB_dbl_f64 do { STORE64_B_(p, t); } while (0)
143#define CONV_STOREL_dbl_f64 do { STORE64_L_(p, t); } while (0)
144
145/* --- @fltfmt_CTYtoFTYE@ --- *
146 *
147 * Arguments: @octet *p@ = output pointer
148 * @float x@, @double x@ = value to convert
149 * @unsigned r@ = rounding mode
150 *
151 * Returns: Error flags (@FLTERR_...@).
152 *
153 * Use: Encode a native C floating-point value in an external format.
154 *
155 * The @CTY@ is an abbreviation for a C type: @flt@ for @float@,
156 * or @dbl@ for @double@; @fty@ is an abbreviation for the
157 * external format, @f32@ for IEEE Binary32, or @f64@ for IEEE
158 * Binary64; and @E@ is @l@ for little-endian or @b@ for
159 * big-endian byte order. Not all combinations are currently
160 * supported.
161 *
162 * On platforms where the external format is used natively,
163 * these functions are simple data copies.
164 */
165
166#define DEF_CONV(ctype, cty, fty) \
167 unsigned fltfmt_##cty##to##fty##l(octet *p, ctype x, unsigned r) \
168 { \
169 unsigned rc = 0; CONV_DECLS_##cty##_##fty; \
170 \
171 CONV_LOAD_##cty##_##fty; \
dc6eea4e 172 CONV_FROBNAN##cty##_##fty; \
b1a20bee
MW
173 CONV_STOREL_##cty##_##fty; \
174 return (rc); \
175 } \
176 \
177 unsigned fltfmt_##cty##to##fty##b(octet *p, ctype x, unsigned r) \
178 { \
179 unsigned rc = 0; CONV_DECLS_##cty##_##fty; \
180 \
181 CONV_LOAD_##cty##_##fty; \
dc6eea4e 182 CONV_FROBNAN##cty##_##fty; \
b1a20bee
MW
183 CONV_STOREB_##cty##_##fty; \
184 return (rc); \
185 }
186
187CONVERSIONS(DEF_CONV)
188
189#undef DEF_CONV
190
191/* --- @fltfmt_FTYEtoCTY@ --- *
192 *
193 * Arguments: @float *z_out@, @double *z_out@ = storage for output
194 * @const octet *p@ = input pointer
195 * @unsigned r@ = rounding mode
196 *
197 * Returns: Error flags (@FLTERR_...@).
198 *
199 * Use: Decodes a floating point value in an external format into a
200 * native value.
201 *
202 * The naming conventions are the same as for @fltfmt_dbltof64b@
203 * above.
204 *
205 * On platforms where the external format is used natively,
206 * these functions are simple data copies.
207 */
208
209#define DEF_CONV(ctype, cty, fty) \
210 unsigned fltfmt_##fty##lto##cty(ctype *z_out, const octet *p, unsigned r) \
211 { \
212 unsigned rc = 0; CONV_DECLS_##cty##_##fty; \
213 \
214 CONV_LOADL_##cty##_##fty; \
dc6eea4e 215 CONV_FROBNAN##cty##_##fty; \
b1a20bee
MW
216 CONV_STORE_##cty##_##fty; \
217 return (rc); \
218 } \
219 \
220 unsigned fltfmt_##fty##bto##cty(ctype *z_out, const octet *p, unsigned r) \
221 { \
222 unsigned rc = 0; CONV_DECLS_##cty##_##fty; \
223 \
224 CONV_LOADB_##cty##_##fty; \
dc6eea4e 225 CONV_FROBNAN##cty##_##fty; \
b1a20bee
MW
226 CONV_STORE_##cty##_##fty; \
227 return (rc); \
228 }
229
230CONVERSIONS(DEF_CONV)
231
232#undef DEF_CONV
233
234/*----- That's all, folks -------------------------------------------------*/