chiark / gitweb /
@@@ 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 -------------------------------------------------*/