X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/e5b61a8dec3586f96d25bd3ef454176526ff0f69..1c3d4cf54a0edd484c4405f5332d39bb17f1aee0:/m4/mdw-uint-bits.m4 diff --git a/m4/mdw-uint-bits.m4 b/m4/mdw-uint-bits.m4 new file mode 100644 index 00000000..d5e678fa --- /dev/null +++ b/m4/mdw-uint-bits.m4 @@ -0,0 +1,91 @@ +dnl -*-autoconf-*- + +### SYNOPSIS +### +### dnl mdw_UINT_BITS(TYPE, ABBREV) +### +### DESCRIPTION +### +### Defines ABBREV_BITS to be the number of bits representable by the +### unsigned type named TYPE. This works even if the compiler in question +### is a cross-compiler, and correctly handles systems without 8-bit bytes, +### or which have hidden bits in their integer representations. +### +### LICENSE +### +### Copyright (c) 2013 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 Algorithm: +dnl +dnl We first find an upper bound on the number of bits in the type as +dnl sizeof(TYPE) * CHAR_BIT. This is usually a good guess at the actual +dnl value, since most modern systems don't have hidden bits, so we test to +dnl see if it's correct. If not, we start a binary search to find the true +dnl value. +dnl +dnl To test a guess n, we form X = (TYPE)~(TYPE)0, which is the largest value +dnl representable as a TYPE, and attempt to shift it right by n places. This +dnl is a little subtle, since shifting by more than the word length is +dnl undefined behaviour. The implementation isn't completely perfect. It +dnl assumes that a shift of 15 bits must be allowed (which is reasonable, +dnl since an int must be at least 16 bits, and the standard integer +dnl promotions will map shorter integer types to an int). If n > 15, we +dnl shift down in two stages, once by dividing by 2^15 = 32768, and once by +dnl shifting by n - 15; otherwise we just shift. (This strange chicanery is +dnl to deal with Microsoft compilers which incorrectly `optimize' adjacent +dnl correct shifts into a single invalid one.) If X >> n is nonzero then n +dnl is too small; if X >> (n - 1) is zero then n is too large; if neither +dnl condition holds then n is correct. +dnl +dnl This is, unfortunately, logarithmic if the initial guess is wrong, but +dnl that will happen rarely on interesting platforms. Sites wanting to speed +dnl up the configuration process can pre-seed the configuration cache. If +dnl anyone really cares, we can detect a native compiler (as opposed to a +dnl cross-compiler) and do the binary-search in C. + +# Serial 1 +AC_DEFUN([mdw_UINT_BITS], + [AC_CACHE_CHECK([size of type `$1' in bits], [mdw_cv_$2_bits], + [mdw_PROBE_CONSTANT([guess], [sizeof($1) * CHAR_BIT], [ +#include +#ifdef HAVE_STDINT_H +# include +#endif]) + down=0 + while :; do + mdw_PROBE_CONSTANT([answer], + [low($guess) ? -1 : low($guess - 1) ? 0 : +1], [ +#ifdef HAVE_STDINT_H +# include +#endif +#define srs(x, n) ((n) <= 15 ? (x) >> (n) : ((x)/32768) >> ((n) - 15)) +#define max (($1)~($1)0 | 0u) +#define low(b) (srs(max, b) != 0) +]) + case "$answer" in + 0) break;; + 1) up=$guess;; + -1) down=$guess;; + esac + guess=$(expr \( $up + $down \) / 2) + done + mdw_cv_$2_bits=$guess]) + AS_TR_SH($2_bits)=$mdw_cv_$2_bits + AC_DEFINE_UNQUOTED(AS_TR_CPP([$2_BITS]), [$mdw_cv_$2_bits], + [number of bits in an object of type `$1'])])