chiark / gitweb /
@@@ fltfmt wip
[mLib] / utils / fltfmt-convert.c
1 /* -*-c-*-
2  *
3  * Direct 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 #if defined(__hppa__) || (defined(__mips__) && !defined(__mips_nan2008))
44 #  define FROB_NANS
45 #endif
46
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
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)
69 #  else
70 #    define CONV_FROBNANflt_f32 do ; while (0)
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)
85 #  define CONV_FROBNANflt_f32 do ; while (0)
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
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        }                                                                \
120      } while (0)
121 #  else
122 #    define CONV_FROBNANdbl_f64 do ; while (0)
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)
138 #  define CONV_FROBNANdbl_f64 do ; while (0)
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;                                            \
172     CONV_FROBNAN##cty##_##fty;                                          \
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;                                            \
182     CONV_FROBNAN##cty##_##fty;                                          \
183     CONV_STOREB_##cty##_##fty;                                          \
184     return (rc);                                                        \
185   }
186
187 CONVERSIONS(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;                                           \
215     CONV_FROBNAN##cty##_##fty;                                          \
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;                                           \
225     CONV_FROBNAN##cty##_##fty;                                          \
226     CONV_STORE_##cty##_##fty;                                           \
227     return (rc);                                                        \
228   }
229
230 CONVERSIONS(DEF_CONV)
231
232 #undef DEF_CONV
233
234 /*----- That's all, folks -------------------------------------------------*/