Commit | Line | Data |
---|---|---|
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 | ||
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; \ | |
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 | ||
230 | CONVERSIONS(DEF_CONV) | |
231 | ||
232 | #undef DEF_CONV | |
233 | ||
234 | /*----- That's all, folks -------------------------------------------------*/ |