@@@ fltfmt mess
[mLib] / m4 / mdw-probe-fltfmt.m4
CommitLineData
b1a20bee
MW
1dnl -*-autoconf-*-
2
3### SYNOPSIS
4###
5### mdw_PROBE_FLTFMT
6###
7### DESCRIPTION
8###
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
12### are a bitmask:
13###
14### * `FLTFMT_ORGMASK' is a bitmask covering the `organization' field,
15### which identifies the organization which defined the format.
16###
17### -- `FLTFMT_IEEE' identifies IEEE 754.
18### -- `FLTFMT_INTEL' identifies Intel.
19###
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.
23###
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
28### format.
29###
30### * `FLTFMT_ENDMASK' is a bitmask covering the `endian' field, which
31### describes the byte ordering convention used.
32###
33### -- `FLTFMT_LE' means little-endian format.
34###
35### -- `FLTFMT_BE' means big-endian format.
36###
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.
41###
42### Other conventions exist and support for them may be added later.
43###
44### Finally, there are predefined values for relevant combinations of
45### format codes and byte orderings:
46###
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'.
51###
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.)
55###
56### This macro works correctly when cross-compiling.
57###
58### LICENSE
59###
60### Copyright (c) 2024 Mark Wooding <mdw@distorted.org.uk>
61###
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.
66###
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.
71###
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/>.
74###
75### In particular, no exception to the GPL is granted regarding generated
76### `configure' scripts which are the output of Autoconf.
77
78dnl Principle of operation:
79dnl
80dnl The essential trick here lies in finding floating-point numbers whose
81dnl encoding, in various formats of interest, happen to be recognizable
82dnl diagnostic text strings. The structure definitions provide some space
83dnl for framing text which allows us to scrape the resulting diagnostic
84dnl strings from the object file.
85dnl
86dnl IEEE formats conveniently don't impose any restrictions on the contents
87dnl of the fraction field because there's a hidden bit. The Intel x87
88dnl double-extended format makes the most significant bit explicit, and also
89dnl expects normalization, which means that the top bit of the fraction bytes
90dnl must be set, so everything gets quite ugly. Worse, the actual data is 10
91dnl bytes long, but it sits in a 16-byte field to force alignment in vectors,
92dnl with the result that there are unavoidably zero bytes in our diagnostic
93dnl output. Different tools respond to these differently; e.g., GNU sed(1)
94dnl just writes out the zero bytes like they were any other character, while
95dnl Busybox sed(1) terminates the output line. As a result, we have to be
96dnl rather more flexible about matching this than I'd really like. (Messing
97dnl about with compiler-specific hacks for structure packing won't help here
98dnl because the analysis code still has to cope with compilers which don't
99dnl have those hacks.)
100
101# Serial 1
102AC_COPYRIGHT([
103Portions copyright (c) 2024 Mark Wooding.
104
105This configure script is free software: you can redistribute it and/or
106modify it under he terms of the GNU General Public License as published
107by the Free Software Foundation, either version 2 of the License, or
108(at your option) any later version.])
109
110AC_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([
114
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.
119 *
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
123 * for more details.
124 *
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/>.
127 */
128
129@%:@include <float.h>
130
131@%:@define DEFFLTDIAG(ty, type) \
132 struct fltdiag_@%:@@%:@ty { char top@<:@48@:>@; type x; char tail@<:@4@:>@; }
133
134DEFFLTDIAG(flt, float);
135
136static const struct fltdiag_flt flt_ieee_f32 = {
137 "\0\0\0\0\0\0\0\0\n@@@ mdw-probe-fltfmt float ieee-f32 = >",
138 781.0352,
139 "<\n\0\0"
140};
141@%:@define DO_FLT_IEEE_F32 DO(flt_ieee_f32)
142
143DEFFLTDIAG(dbl, double);
144
145@%:@if DBL_MAX_10_EXP > 40
146static 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,
149 "<\n\0\0"
150};
151@%:@ define DO_DBL_IEEE_F64 DO(dbl_ieee_f64)
152@%:@else
153@%:@ define DO_DBL_IEEE_F64
154@%:@endif
155
156DEFFLTDIAG(ldbl, long double);
157
158@%:@if LDBL_MAX_10_EXP > 40
159static const struct fltdiag_ldbl ldbl_ieee_f64 = {
160 "\0\0\n@@@ mdw-probe-fltfmt long-double ieee-f64 = >",
161 1.5839800103804824e40,
162 "<\n\0\0"
163};
164@%:@ define DO_LDBL_IEEE_F64 DO(ldbl_ieee_f64)
165@%:@else
166@%:@ define DO_LDBL_IEEE_F64
167@%:@endif
168
169@%:@if LDBL_MAX_10_EXP > 1257
170static const struct fltdiag_ldbl ldbl_ieee_f128 = {
171 "\0\n@@@ mdw-probe-fltfmt long-double ieee-f128 = >",
172 1.6487728650847311136108983312706536e+1257L,
173 "<\n\0\0"
174};
175@%:@ define DO_LDBL_IEEE_F128 DO(ldbl_ieee_f128)
176@%:@else
177@%:@ define DO_LDBL_IEEE_F128
178@%:@endif
179
180@%:@if LDBL_MAX_10_EXP > 793
181static const struct fltdiag_ldbl ldbl_intel_f80 = {
182 "\0\n@@@ mdw-probe-fltfmt long-double intel-f80 = >",
183 1.2806567921142816197e+793L,
184 "<\n\0\0"
185};
186@%:@ define DO_LDBL_INTEL_F80 DO(ldbl_intel_f80)
187@%:@else
188@%:@ define DO_LDBL_INTEL_F80
189@%:@endif
190
191@%:@include <stdio.h>
192int main(void)
193{
194@%:@define DO(var) fwrite(&var, sizeof(var), 1, stdout)
195 DO_FLT_IEEE_F32;
196 DO_DBL_IEEE_F64;
197 DO_LDBL_IEEE_F64;
198 DO_LDBL_IEEE_F128;
199 DO_LDBL_IEEE_F128;
200 DO_LDBL_INTEL_F80;
201@%:@undef DO
202 return (0);
203}
204])],
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