Commit | Line | Data |
---|---|---|
b1a20bee MW |
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 -------------------------------------------------*/ |