9 ### Attempts to determine the target system's floating-point formats.
10 ### The macros `FLT_FORMAT', `DBL_FORMAT', and `LDBL_FORMAT' are defined if
11 ### the corresponding formats are recognized. The values of these macros
14 ### * `FLTFMT_ORGMASK' is a bitmask covering the `organization' field,
15 ### which identifies the organization which defined the format.
17 ### -- `FLTFMT_IEEE' identifies IEEE 754.
18 ### -- `FLTFMT_INTEL' identifies Intel.
20 ### * `FLTFMT_TYPEMASK' is a bitmask covering the `type' field, which
21 ### must be interpreted together with the organization field to
22 ### determine the format.
24 ### -- `FLTFMT_IEEE_F32' is the IEEE 754 `binary32' format.
25 ### -- `FLTFMT_IEEE_F64' is the IEEE 754 `binary64' format.
26 ### -- `FLTFMT_IEEE_F128' is the IEEE 754 `binary128' format.
27 ### -- `FLTFMT_INTEL_F80' is the Intel x87 80-bit double-extended
30 ### * `FLTFMT_ENDMASK' is a bitmask covering the `endian' field, which
31 ### describes the byte ordering convention used.
33 ### -- `FLTFMT_LE' means little-endian format.
35 ### -- `FLTFMT_BE' means big-endian format.
37 ### -- `FLTFMT_ARME' means `Acorn's ridiculous mixed-endian' format,
38 ### used by the ARM FPA, which stored the a `binary64' value as
39 ### two 32-bit words, most significant word first, but with the
40 ### individual words stored in little-endian byte order.
42 ### Other conventions exist and support for them may be added later.
44 ### Finally, there are predefined values for relevant combinations of
45 ### format codes and byte orderings:
47 ### * `FLTFMT_IEEE_F32_LE' and `FLTFMT_IEEE_F32_BE';
48 ### * `FLTFMT_IEEE_F64_LE' and `FLTFMT_IEEE_F64_BE';
49 ### * `FLTFMT_IEEE_F128_LE' and `FLTFMT_IEEE_F128_BE';
50 ### * `FLTFMT_INTEL_F80_LE' and `FLTFMT_INTEL_F80_BE'.
52 ### (I don't know of anything which uses Intel's double-extended format in
53 ### big-endian order, but it was easy enough to check for. The IEEE
54 ### formats are used on ARM64 and z/Architecture with opposite byte order.)
56 ### This macro works correctly when cross-compiling.
60 ### Copyright (c) 2024 Mark Wooding <mdw@distorted.org.uk>
62 ### This program is free software: you can redistribute it and/or modify it
63 ### under the terms of the GNU General Public License as published by the
64 ### Free Software Foundation, either version 2 of the License, or (at your
65 ### option) any later version.
67 ### This program is distributed in the hope that it will be useful, but
68 ### WITHOUT ANY WARRANTY; without even the implied warranty of
69 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
70 ### General Public License for more details.
72 ### You should have received a copy of the GNU General Public License along
73 ### with this program. If not, see <http://www.gnu.org/licenses/>.
75 ### In particular, no exception to the GPL is granted regarding generated
76 ### `configure' scripts which are the output of Autoconf.
78 dnl Principle of operation:
80 dnl The essential trick here lies in finding floating-point numbers whose
81 dnl encoding, in various formats of interest, happen to be recognizable
82 dnl diagnostic text strings. The structure definitions provide some space
83 dnl for framing text which allows us to scrape the resulting diagnostic
84 dnl strings from the object file.
86 dnl IEEE formats conveniently don't impose any restrictions on the contents
87 dnl of the fraction field because there's a hidden bit. The Intel x87
88 dnl double-extended format makes the most significant bit explicit, and also
89 dnl expects normalization, which means that the top bit of the fraction bytes
90 dnl must be set, so everything gets quite ugly. Worse, the actual data is 10
91 dnl bytes long, but it sits in a 16-byte field to force alignment in vectors,
92 dnl with the result that there are unavoidably zero bytes in our diagnostic
93 dnl output. Different tools respond to these differently; e.g., GNU sed(1)
94 dnl just writes out the zero bytes like they were any other character, while
95 dnl Busybox sed(1) terminates the output line. As a result, we have to be
96 dnl rather more flexible about matching this than I'd really like. (Messing
97 dnl about with compiler-specific hacks for structure packing won't help here
98 dnl because the analysis code still has to cope with compilers which don't
99 dnl have those hacks.)
103 Portions copyright (c) 2024 Mark Wooding.
105 This configure script is free software: you can redistribute it and/or
106 modify it under he terms of the GNU General Public License as published
107 by the Free Software Foundation, either version 2 of the License, or
108 (at your option) any later version.])
110 AC_DEFUN([mdw_PROBE_FLTFMT],
111 [AC_CACHE_CHECK([floating-point representations], [mdw_cv_fltfmt],
112 [mdw_fltfmt=nil mdw_dblfmt=nil mdw_ldblfmt=nil
113 AC_LINK_IFELSE([AC_LANG_SOURCE([
115 /* The following program is copyright (c) 2024 Mark Wooding. It is free
116 * software: you can redistribute it and/or modify it under the terms of the
117 * GNU General Public License as published by the Free Software Foundation,
118 * either version 2 of the License, or (at your option) any later version.
120 * This program is distributed in the hope that it will be useful, but
121 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
122 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
125 * You should have received a copy of the GNU General Public License along
126 * with this program. If not, see <http://www.gnu.org/licenses/>.
129 @%:@include <float.h>
131 @%:@define DEFFLTDIAG(ty, type) \
132 struct fltdiag_@%:@@%:@ty { char top@<:@48@:>@; type x; char tail@<:@4@:>@; }
134 DEFFLTDIAG(flt, float);
136 static const struct fltdiag_flt flt_ieee_f32 = {
137 "\0\0\0\0\0\0\0\0\n@@@ mdw-probe-fltfmt float ieee-f32 = >",
141 @%:@define DO_FLT_IEEE_F32 DO(flt_ieee_f32)
143 DEFFLTDIAG(dbl, double);
145 @%:@if DBL_MAX_10_EXP > 40
146 static const struct fltdiag_dbl dbl_ieee_f64 = {
147 "\0\0\0\0\0\0\0\n@@@ mdw-probe-fltfmt double ieee-f64 = >",
148 1.5839800103804824e40,
151 @%:@ define DO_DBL_IEEE_F64 DO(dbl_ieee_f64)
153 @%:@ define DO_DBL_IEEE_F64
156 DEFFLTDIAG(ldbl, long double);
158 @%:@if LDBL_MAX_10_EXP > 40
159 static const struct fltdiag_ldbl ldbl_ieee_f64 = {
160 "\0\0\n@@@ mdw-probe-fltfmt long-double ieee-f64 = >",
161 1.5839800103804824e40,
164 @%:@ define DO_LDBL_IEEE_F64 DO(ldbl_ieee_f64)
166 @%:@ define DO_LDBL_IEEE_F64
169 @%:@if LDBL_MAX_10_EXP > 1257
170 static const struct fltdiag_ldbl ldbl_ieee_f128 = {
171 "\0\n@@@ mdw-probe-fltfmt long-double ieee-f128 = >",
172 1.6487728650847311136108983312706536e+1257L,
175 @%:@ define DO_LDBL_IEEE_F128 DO(ldbl_ieee_f128)
177 @%:@ define DO_LDBL_IEEE_F128
180 @%:@if LDBL_MAX_10_EXP > 793
181 static const struct fltdiag_ldbl ldbl_intel_f80 = {
182 "\0\n@@@ mdw-probe-fltfmt long-double intel-f80 = >",
183 1.2806567921142816197e+793L,
186 @%:@ define DO_LDBL_INTEL_F80 DO(ldbl_intel_f80)
188 @%:@ define DO_LDBL_INTEL_F80
191 @%:@include <stdio.h>
194 @%:@define DO(var) fwrite(&var, sizeof(var), 1, stdout)
205 [sed -n "/^@@@ mdw-probe-fltfmt @<:@^ @:>@* @<:@^ @:>@* = >/p" \
206 conftest$EXEEXT >conftest.out
207 while read _at _tag ty fmt _eq diag; do
208 case $ty,$fmt,$diag in
209 "float,ieee-f32,>ABCD<") mdw_fltfmt=ieee-f32-le ;;
210 "float,ieee-f32,>DCBA<") mdw_fltfmt=ieee-f32-be ;;
211 "double,ieee-f64,>ABCDEFGH<") mdw_dblfmt=ieee-f64-le ;;
212 "double,ieee-f64,>EFGHABCD<") mdw_dblfmt=ieee-f64-arme ;;
213 "double,ieee-f64,>HGFEDCBA<") mdw_dblfmt=ieee-f64-be ;;
214 "long-double,ieee-f64,>ABCDEFGH<") mdw_ldblfmt=ieee-f64-le ;;
215 "long-double,ieee-f64,>HGFEDCBA<") mdw_ldblfmt=ieee-f64-be ;;
216 "long-double,ieee-f128,>ABCDEFGHIJKLMNOP<")
217 mdw_ldblfmt=ieee-f128-le ;;
218 "long-double,ieee-f128,>PONMLKJIHGFEDCBA<")
219 mdw_ldblfmt=ieee-f128-be ;;
220 "long-double,intel-f80,>ABCDEFGÈIJ" | \
221 "long-double,intel-f80,>ABCDEFGÈIJ"*"<")
222 mdw_ldblfmt=intel-f80-le ;;
223 "long-double,intel-f80,>JIÈGFEDCBA" | \
224 "long-double,intel-f80,>JIÈGFEDCBA"*"<")
225 mdw_ldblfmt=intel-f80-be ;;
228 mdw_cv_fltfmt="float=$mdw_fltfmt"
229 mdw_cv_fltfmt="$mdw_cv_fltfmt double=$mdw_dblfmt"
230 mdw_cv_fltfmt="$mdw_cv_fltfmt long-double=$mdw_ldblfmt"])
232 AC_DEFINE([FLTFMT_ENDMASK], [0x0300],
233 [mask for byte ordering])
234 AC_DEFINE([FLTFMT_LE], [0x0000],
235 [little-endian floating-point storage])
236 AC_DEFINE([FLTFMT_BE], [0x0100],
237 [big-endian floating-point storage])
238 AC_DEFINE([FLTFMT_ARME], [0x0200],
239 [Acorn's ridiculous mixed-endian floating-point storage])
241 AC_DEFINE([FLTFMT_ORGMASK], [0xfc00],
242 [mask for floating-point organization id])
243 AC_DEFINE([FLTFMT_TYPEMASK], [0x00ff],
244 [mask for floating-point format type])
246 AC_DEFINE([FLTFMT_UNKNOWN], [0x0000],
247 [unrecognized floating-point format])
249 AC_DEFINE([FLTFMT_IEEE], [0x0400],
250 [floating-point organization id for IEEE 754])
251 AC_DEFINE([FLTFMT_IEEE_F32], [FLTFMT_IEEE | 5],
252 [IEEE 754 `binary32' format])
253 AC_DEFINE([FLTFMT_IEEE_F32_LE], [(FLTFMT_IEEE_F32 | FLTFMT_LE)],
254 [IEEE `binary32' format, little-endian])
255 AC_DEFINE([FLTFMT_IEEE_F32_BE], [(FLTFMT_IEEE_F32 | FLTFMT_BE)],
256 [IEEE `binary32' format, big-endian])
257 AC_DEFINE([FLTFMT_IEEE_F64], [FLTFMT_IEEE | 6],
258 [IEEE 754 `binary32' format])
259 AC_DEFINE([FLTFMT_IEEE_F64_LE], [(FLTFMT_IEEE_F64 | FLTFMT_LE)],
260 [IEEE `binary64' format, little-endian])
261 AC_DEFINE([FLTFMT_IEEE_F64_ARME], [(FLTFMT_IEEE_F64 | FLTFMT_ARME)],
262 [IEEE `binary64' format, Acorn ridiculous mixed-endian])
263 AC_DEFINE([FLTFMT_IEEE_F64_BE], [(FLTFMT_IEEE_F64 | FLTFMT_BE)],
264 [IEEE `binary64' format, big-endian])
265 AC_DEFINE([FLTFMT_IEEE_F128], [FLTFMT_IEEE | 7],
266 [IEEE 754 `binary32' format])
267 AC_DEFINE([FLTFMT_IEEE_F128_LE], [(FLTFMT_IEEE_F128 | FLTFMT_LE)],
268 [IEEE `binary128' format, little-endian])
269 AC_DEFINE([FLTFMT_IEEE_F128_BE], [(FLTFMT_IEEE_F128 | FLTFMT_BE)],
270 [IEEE `binary128' format, big-endian])
272 AC_DEFINE([FLTFMT_INTEL], [0x0800],
273 [floating-point organization id for Intel])
274 AC_DEFINE([FLTFMT_INTEL_F80], [FLTFMT_INTEL | 80],
275 [Intel x87 double-extended format])
276 AC_DEFINE([FLTFMT_INTEL_F80_LE], [(FLTFMT_INTEL_F80 | FLTFMT_LE)],
277 [Intel x86 double-extended format, little-endian])
278 AC_DEFINE([FLTFMT_INTEL_F80_BE], [(FLTFMT_INTEL_F80 | FLTFMT_BE)],
279 [Intel x87 double-extended format, big-endian])
281 AH_TEMPLATE([FLT_FORMAT],
282 [floating point format for `float' type])
283 AH_TEMPLATE([DBL_FORMAT],
284 [floating point format for `double' type])
285 AH_TEMPLATE([LDBL_FORMAT],
286 [floating point format for `long double' type])
288 for w in $mdw_cv_fltfmt; do
289 ty=${w%=*} fmt=${w@%:@*=}
293 long-double) var=LDBL ;;
294 *) AC_MSG_ERROR([unexpected floating-point type `$ty']) ;;
297 nil) value=UNKNOWN ;;
298 ieee-f32-le) value=IEEE_F32_LE ;;
299 ieee-f32-be) value=IEEE_F32_BE ;;
300 ieee-f64-le) value=IEEE_F64_LE ;;
301 ieee-f64-arme) value=IEEE_F64_ARME ;;
302 ieee-f64-be) value=IEEE_F64_BE ;;
303 ieee-f128-le) value=IEEE_F128_LE ;;
304 ieee-f128-be) value=IEEE_F128_BE ;;
305 intel-f80-le) value=INTEL_F80_LE ;;
306 intel-f80-be) value=INTEL_F80_BE ;;
307 *) AC_MSG_ERROR([unexpected floating-point format `$fmt']) ;;
309 AC_DEFINE_UNQUOTED([${var}_FORMAT], [FLTFMT_$value])