dnl -*-autoconf-*- ### SYNOPSIS ### ### mdw_PROBE_FLTFMT ### ### DESCRIPTION ### ### Attempts to determine the target system's floating-point formats. ### The macros `FLT_FORMAT', `DBL_FORMAT', and `LDBL_FORMAT' are defined if ### the corresponding formats are recognized. The values of these macros ### are a bitmask: ### ### * `FLTFMT_ORGMASK' is a bitmask covering the `organization' field, ### which identifies the organization which defined the format. ### ### -- `FLTFMT_IEEE' identifies IEEE 754. ### -- `FLTFMT_INTEL' identifies Intel. ### ### * `FLTFMT_TYPEMASK' is a bitmask covering the `type' field, which ### must be interpreted together with the organization field to ### determine the format. ### ### -- `FLTFMT_IEEE_F32' is the IEEE 754 `binary32' format. ### -- `FLTFMT_IEEE_F64' is the IEEE 754 `binary64' format. ### -- `FLTFMT_IEEE_F128' is the IEEE 754 `binary128' format. ### -- `FLTFMT_INTEL_F80' is the Intel x87 80-bit double-extended ### format. ### ### * `FLTFMT_ENDMASK' is a bitmask covering the `endian' field, which ### describes the byte ordering convention used. ### ### -- `FLTFMT_LE' means little-endian format. ### ### -- `FLTFMT_BE' means big-endian format. ### ### -- `FLTFMT_ARME' means `Acorn's ridiculous mixed-endian' format, ### used by the ARM FPA, which stored the a `binary64' value as ### two 32-bit words, most significant word first, but with the ### individual words stored in little-endian byte order. ### ### Other conventions exist and support for them may be added later. ### ### Finally, there are predefined values for relevant combinations of ### format codes and byte orderings: ### ### * `FLTFMT_IEEE_F32_LE' and `FLTFMT_IEEE_F32_BE'; ### * `FLTFMT_IEEE_F64_LE' and `FLTFMT_IEEE_F64_BE'; ### * `FLTFMT_IEEE_F128_LE' and `FLTFMT_IEEE_F128_BE'; ### * `FLTFMT_INTEL_F80_LE' and `FLTFMT_INTEL_F80_BE'. ### ### (I don't know of anything which uses Intel's double-extended format in ### big-endian order, but it was easy enough to check for. The IEEE ### formats are used on ARM64 and z/Architecture with opposite byte order.) ### ### This macro works correctly when cross-compiling. ### ### LICENSE ### ### Copyright (c) 2024 Mark Wooding ### ### This program is free software: you can redistribute it and/or modify it ### under the terms of the GNU General Public License as published by the ### Free Software Foundation, either version 2 of the License, or (at your ### option) any later version. ### ### This program is distributed in the hope that it will be useful, but ### WITHOUT ANY WARRANTY; without even the implied warranty of ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ### General Public License for more details. ### ### You should have received a copy of the GNU General Public License along ### with this program. If not, see . ### ### In particular, no exception to the GPL is granted regarding generated ### `configure' scripts which are the output of Autoconf. dnl Principle of operation: dnl dnl The essential trick here lies in finding floating-point numbers whose dnl encoding, in various formats of interest, happen to be recognizable dnl diagnostic text strings. The structure definitions provide some space dnl for framing text which allows us to scrape the resulting diagnostic dnl strings from the object file. dnl dnl IEEE formats conveniently don't impose any restrictions on the contents dnl of the fraction field because there's a hidden bit. The Intel x87 dnl double-extended format makes the most significant bit explicit, and also dnl expects normalization, which means that the top bit of the fraction bytes dnl must be set, so everything gets quite ugly. Worse, the actual data is 10 dnl bytes long, but it sits in a 16-byte field to force alignment in vectors, dnl with the result that there are unavoidably zero bytes in our diagnostic dnl output. Different tools respond to these differently; e.g., GNU sed(1) dnl just writes out the zero bytes like they were any other character, while dnl Busybox sed(1) terminates the output line. As a result, we have to be dnl rather more flexible about matching this than I'd really like. (Messing dnl about with compiler-specific hacks for structure packing won't help here dnl because the analysis code still has to cope with compilers which don't dnl have those hacks.) # Serial 1 AC_COPYRIGHT([ Portions copyright (c) 2024 Mark Wooding. This configure script is free software: you can redistribute it and/or modify it under he terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.]) AC_DEFUN([mdw_PROBE_FLTFMT], [AC_CACHE_CHECK([floating-point representations], [mdw_cv_fltfmt], [mdw_fltfmt=nil mdw_dblfmt=nil mdw_ldblfmt=nil AC_LINK_IFELSE([AC_LANG_SOURCE([ /* The following program is copyright (c) 2024 Mark Wooding. It is free * software: you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation, * either version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ @%:@include @%:@define DEFFLTDIAG(ty, type) \ struct fltdiag_@%:@@%:@ty { char top@<:@48@:>@; type x; char tail@<:@4@:>@; } DEFFLTDIAG(flt, float); static const struct fltdiag_flt flt_ieee_f32 = { "\0\0\0\0\0\0\0\0\n@@@ mdw-probe-fltfmt float ieee-f32 = >", 781.0352, "<\n\0\0" }; @%:@define DO_FLT_IEEE_F32 DO(flt_ieee_f32) DEFFLTDIAG(dbl, double); @%:@if DBL_MAX_10_EXP > 40 static const struct fltdiag_dbl dbl_ieee_f64 = { "\0\0\0\0\0\0\0\n@@@ mdw-probe-fltfmt double ieee-f64 = >", 1.5839800103804824e40, "<\n\0\0" }; @%:@ define DO_DBL_IEEE_F64 DO(dbl_ieee_f64) @%:@else @%:@ define DO_DBL_IEEE_F64 @%:@endif DEFFLTDIAG(ldbl, long double); @%:@if LDBL_MAX_10_EXP > 40 static const struct fltdiag_ldbl ldbl_ieee_f64 = { "\0\0\n@@@ mdw-probe-fltfmt long-double ieee-f64 = >", 1.5839800103804824e40, "<\n\0\0" }; @%:@ define DO_LDBL_IEEE_F64 DO(ldbl_ieee_f64) @%:@else @%:@ define DO_LDBL_IEEE_F64 @%:@endif @%:@if LDBL_MAX_10_EXP > 1257 static const struct fltdiag_ldbl ldbl_ieee_f128 = { "\0\n@@@ mdw-probe-fltfmt long-double ieee-f128 = >", 1.6487728650847311136108983312706536e+1257L, "<\n\0\0" }; @%:@ define DO_LDBL_IEEE_F128 DO(ldbl_ieee_f128) @%:@else @%:@ define DO_LDBL_IEEE_F128 @%:@endif @%:@if LDBL_MAX_10_EXP > 793 static const struct fltdiag_ldbl ldbl_intel_f80 = { "\0\n@@@ mdw-probe-fltfmt long-double intel-f80 = >", 1.2806567921142816197e+793L, "<\n\0\0" }; @%:@ define DO_LDBL_INTEL_F80 DO(ldbl_intel_f80) @%:@else @%:@ define DO_LDBL_INTEL_F80 @%:@endif @%:@include int main(void) { @%:@define DO(var) fwrite(&var, sizeof(var), 1, stdout) DO_FLT_IEEE_F32; DO_DBL_IEEE_F64; DO_LDBL_IEEE_F64; DO_LDBL_IEEE_F128; DO_LDBL_IEEE_F128; DO_LDBL_INTEL_F80; @%:@undef DO return (0); } ])], [sed -n "/^@@@ mdw-probe-fltfmt @<:@^ @:>@* @<:@^ @:>@* = >/p" \ conftest$EXEEXT >conftest.out while read _at _tag ty fmt _eq diag; do case $ty,$fmt,$diag in "float,ieee-f32,>ABCD<") mdw_fltfmt=ieee-f32-le ;; "float,ieee-f32,>DCBA<") mdw_fltfmt=ieee-f32-be ;; "double,ieee-f64,>ABCDEFGH<") mdw_dblfmt=ieee-f64-le ;; "double,ieee-f64,>EFGHABCD<") mdw_dblfmt=ieee-f64-arme ;; "double,ieee-f64,>HGFEDCBA<") mdw_dblfmt=ieee-f64-be ;; "long-double,ieee-f64,>ABCDEFGH<") mdw_ldblfmt=ieee-f64-le ;; "long-double,ieee-f64,>HGFEDCBA<") mdw_ldblfmt=ieee-f64-be ;; "long-double,ieee-f128,>ABCDEFGHIJKLMNOP<") mdw_ldblfmt=ieee-f128-le ;; "long-double,ieee-f128,>PONMLKJIHGFEDCBA<") mdw_ldblfmt=ieee-f128-be ;; "long-double,intel-f80,>ABCDEFGÈIJ" | \ "long-double,intel-f80,>ABCDEFGÈIJ"*"<") mdw_ldblfmt=intel-f80-le ;; "long-double,intel-f80,>JIÈGFEDCBA" | \ "long-double,intel-f80,>JIÈGFEDCBA"*"<") mdw_ldblfmt=intel-f80-be ;; esac done