mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 11:02:59 -04:00
466 lines
14 KiB
Bash
466 lines
14 KiB
Bash
#! /bin/sh
|
|
|
|
# $Id: float-auto.sh,v 1.2 2007/08/24 00:55:33 fredette Exp $
|
|
|
|
# generic/float-auto.sh - automatically generates C code for floating
|
|
# point conversion functions:
|
|
|
|
#
|
|
# Copyright (c) 2004 Matt Fredette
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
# 3. All advertising materials mentioning features or use of this software
|
|
# must display the following acknowledgement:
|
|
# This product includes software developed by Matt Fredette.
|
|
# 4. The name of the author may not be used to endorse or promote products
|
|
# derived from this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
|
|
header=false
|
|
for option
|
|
do
|
|
case $option in
|
|
--header) header=true ;;
|
|
esac
|
|
done
|
|
|
|
PROG=`basename $0`
|
|
cat <<EOF
|
|
/* automatically generated by $PROG, do not edit! */
|
|
|
|
EOF
|
|
if $header; then :; else
|
|
cat <<EOF
|
|
#include <tme/common.h>
|
|
_TME_RCSID("\$Id: float-auto.sh,v 1.2 2007/08/24 00:55:33 fredette Exp $");
|
|
|
|
/* includes: */
|
|
#include <tme/generic/float.h>
|
|
|
|
EOF
|
|
fi
|
|
|
|
# permute over the builtin types:
|
|
#
|
|
for _builtin_type in float double long_double; do
|
|
|
|
# make the builtin type without underscores, and in all caps:
|
|
#
|
|
builtin_type=`echo ${_builtin_type} | sed -e 's/_/ /g'`
|
|
_BUILTIN_TYPE=`echo ${_builtin_type} | tr 'a-z' 'A-Z'`
|
|
|
|
# dispatch on the builtin type to open any protection:
|
|
#
|
|
case ${_builtin_type} in
|
|
long_double)
|
|
echo ; echo "#ifdef _TME_HAVE_${_BUILTIN_TYPE}" ;;
|
|
*) ;;
|
|
esac
|
|
|
|
# if we're generating a header:
|
|
#
|
|
if $header; then
|
|
cat <<EOF
|
|
|
|
/* if possible, this returns a positive or negative infinity
|
|
${builtin_type}, otherwise, this returns the ${builtin_type} value
|
|
closest to that infinity: */
|
|
${builtin_type} tme_float_infinity_${_builtin_type} _TME_P((int));
|
|
|
|
/* if possible, this returns a negative zero ${builtin_type}.
|
|
otherwise, this returns the negative ${builtin_type} value closest
|
|
to zero: */
|
|
${builtin_type} tme_float_negative_zero_${_builtin_type} _TME_P((void));
|
|
EOF
|
|
else
|
|
cat <<EOF
|
|
|
|
/* if possible, this returns a positive or negative infinity
|
|
${builtin_type}, otherwise, this returns the ${builtin_type} value
|
|
closest to that infinity: */
|
|
${builtin_type}
|
|
tme_float_infinity_${_builtin_type}(int negative)
|
|
{
|
|
static int inf_set_${_builtin_type};
|
|
static ${builtin_type} inf_${_builtin_type}[2];
|
|
${builtin_type} inf_test;
|
|
int negative_i;
|
|
|
|
/* make sure that negative can index the inf_${_builtin_type} array: */
|
|
negative = !!negative;
|
|
|
|
/* if the ${builtin_type} infinities have already been set: */
|
|
if (__tme_predict_true(inf_set_${_builtin_type})) {
|
|
return (inf_${_builtin_type}[negative]);
|
|
}
|
|
|
|
/* the ${builtin_type} infinities will be set now: */
|
|
inf_set_${_builtin_type} = TRUE;
|
|
|
|
/* set the positive and negative infinities: */
|
|
for (negative_i = 0; negative_i < 2; negative_i++) {
|
|
|
|
/* start with the limit maximum positive value or limit minimum
|
|
negative value. double this value until either it doesn't
|
|
change or it isn't closer to the desired infinity, and then
|
|
use the previous value: */
|
|
inf_test = FLOAT_MAX_${_BUILTIN_TYPE};
|
|
if (negative_i) {
|
|
inf_test = -inf_test;
|
|
}
|
|
do {
|
|
memcpy((char *) &inf_${_builtin_type}[negative_i], (char *) &inf_test, sizeof(inf_test));
|
|
inf_test *= 2;
|
|
} while (memcmp((char *) &inf_${_builtin_type}[negative_i], (char *) &inf_test, sizeof(inf_test)) != 0
|
|
&& (negative_i
|
|
? inf_test < inf_${_builtin_type}[negative_i]
|
|
: inf_test > inf_${_builtin_type}[negative_i]));
|
|
|
|
/* try to generate the actual infinity by dividing one or negative
|
|
one by zero. if this value is closer to the desired infinity,
|
|
use it: */
|
|
inf_test = (negative_i ? -1.0 : 1.0) / 0.0;
|
|
if (negative_i
|
|
? inf_test < inf_${_builtin_type}[negative_i]
|
|
: inf_test > inf_${_builtin_type}[negative_i]) {
|
|
inf_${_builtin_type}[negative_i] = inf_test;
|
|
}
|
|
}
|
|
|
|
/* return the desired infinity: */
|
|
return (inf_${_builtin_type}[negative]);
|
|
}
|
|
|
|
/* if possible, this returns a negative zero ${builtin_type}.
|
|
otherwise, this returns the negative ${builtin_type} value closest
|
|
to zero: */
|
|
${builtin_type}
|
|
tme_float_negative_zero_${_builtin_type}(void)
|
|
{
|
|
static int nzero_set_${_builtin_type};
|
|
static ${builtin_type} nzero_${_builtin_type};
|
|
${builtin_type} constant_pzero;
|
|
${builtin_type} constant_nzero;
|
|
${builtin_type} nzero_test;
|
|
|
|
/* if the ${builtin_type} negative zero has already been set: */
|
|
if (__tme_predict_true(nzero_set_${_builtin_type})) {
|
|
return (nzero_${_builtin_type});
|
|
}
|
|
|
|
/* the ${builtin_type} negative zero will be set now: */
|
|
nzero_set_${_builtin_type} = TRUE;
|
|
|
|
/* make a +0.0 and a -0.0, that we can do bit-for-bit comparisons with.
|
|
NB that sizeof(${builtin_type}) may cover more bits than are actually
|
|
used by a ${builtin_type}: */
|
|
memset((char *) &constant_pzero, 0, sizeof(constant_pzero));
|
|
memset((char *) &constant_nzero, 0, sizeof(constant_nzero));
|
|
constant_pzero = +0.0;
|
|
constant_nzero = -0.0;
|
|
|
|
/* if -0.0 * -0.0 is bit-for-bit different from -0.0 and is
|
|
bit-for-bit identical to +0.0, use -0.0: */
|
|
memset((char *) &nzero_test, 0, sizeof(nzero_test));
|
|
nzero_test = constant_nzero * constant_nzero;
|
|
if (memcmp((char *) &constant_nzero, (char *) &nzero_test, sizeof(nzero_test)) != 0
|
|
&& memcmp((char *) &constant_pzero, (char *) &nzero_test, sizeof(nzero_test)) == 0) {
|
|
return (nzero_${_builtin_type} = constant_nzero);
|
|
}
|
|
|
|
/* otherwise, start with the limit maximum negative value (which is
|
|
zero minus the limit minimum positive value). halve this value
|
|
until either it doesn't change or it becomes positive zero, and
|
|
then use the previous value: */
|
|
nzero_test = 0 - FLOAT_MIN_${_BUILTIN_TYPE};
|
|
do {
|
|
memcpy((char *) &nzero_${_builtin_type}, (char *) &nzero_test, sizeof(nzero_test));
|
|
nzero_test = nzero_test / 2;
|
|
} while (memcmp((char *) &nzero_${_builtin_type}, (char *) &nzero_test, sizeof(nzero_test)) != 0
|
|
&& memcmp((char *) &constant_pzero, (char *) &nzero_test, sizeof(nzero_test)) != 0);
|
|
return (nzero_${_builtin_type});
|
|
}
|
|
EOF
|
|
fi
|
|
|
|
|
|
# permute over the radices:
|
|
#
|
|
for radix in 2 10; do
|
|
|
|
# if we're generating a header:
|
|
#
|
|
if $header; then
|
|
cat <<EOF
|
|
|
|
/* this returns the radix ${radix} mantissa and exponent of an in-range ${builtin_type}.
|
|
the mantissa is either zero, or in the range [1,${radix}): */
|
|
${builtin_type} tme_float_radix${radix}_mantissa_exponent_${_builtin_type} _TME_P((${builtin_type}, tme_int32_t *));
|
|
|
|
/* this scales a value by adding n to its radix ${radix} exponent: */
|
|
${builtin_type} tme_float_radix${radix}_scale_${_builtin_type} _TME_P((${builtin_type}, tme_int32_t));
|
|
EOF
|
|
continue
|
|
fi
|
|
|
|
# permute over the sign of the exponent:
|
|
#
|
|
for _sign in pos neg; do
|
|
|
|
# make the sign into two operators:
|
|
#
|
|
if test ${_sign} = pos; then sign= ; combine='*' ; else sign=- ; combine='/' ; fi
|
|
|
|
echo ""
|
|
echo "/* a series of ${builtin_type} values of the form ${radix}^${sign}x, where x is a power of two: */"
|
|
echo "static const ${builtin_type} _tme_float_radix${radix}_exponent_bits_${_builtin_type}_${_sign}[] = {"
|
|
exponent=1
|
|
formats_last=
|
|
|
|
while true; do
|
|
|
|
# dispatch on the radix to get the largest factor we will
|
|
# use, its exponent, and a coarse upper bound on this
|
|
# value's exponent in the worst-case radix of two:
|
|
#
|
|
case ${radix} in
|
|
2) exponent_radix2=${exponent} ; x=16777216 ; exponent_x=24 ;;
|
|
10) exponent_radix2=`expr ${exponent} \* 4` ; x=10000 ; exponent_x=4 ;;
|
|
*)
|
|
echo "$PROG internal error: can't handle radix ${radix}" 1>&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# we assume that all floating-point formats that use a
|
|
# radix of two support at least positive and negative
|
|
# exponents of magnitude 16. if this exponent's
|
|
# magnitude is greater than that, dispatch to get the
|
|
# list of floating-point formats that support it:
|
|
#
|
|
formats=
|
|
if test `expr ${exponent_radix2} \> 16` != 0; then
|
|
|
|
# the IEEE 754 types:
|
|
#
|
|
if test `expr ${exponent_radix2} \< 16384` != 0; then
|
|
formats="${formats} | TME_FLOAT_FORMAT_IEEE754_EXTENDED80"
|
|
fi
|
|
if test `expr ${exponent_radix2} \< 1024` != 0; then
|
|
formats="${formats} | TME_FLOAT_FORMAT_IEEE754_DOUBLE"
|
|
fi
|
|
if test `expr ${exponent_radix2} \< 128` != 0; then
|
|
formats="${formats} | TME_FLOAT_FORMAT_IEEE754_SINGLE"
|
|
fi
|
|
|
|
# if we don't know any formats that support this
|
|
# exponent, stop now:
|
|
#
|
|
if test "x${formats}" = x; then
|
|
break
|
|
fi
|
|
|
|
# clean up the formats:
|
|
#
|
|
formats="((TME_FLOAT_FORMAT_${_BUILTIN_TYPE} & ("`echo "${formats}" | sed -e 's%^ | %%'`")) != 0)"
|
|
fi
|
|
|
|
# if the formats have changed:
|
|
#
|
|
if test "x${formats}" != "x${formats_last}"; then
|
|
|
|
# close any old #if first:
|
|
#
|
|
if test "x${formats_last}" != x; then
|
|
echo ""
|
|
echo "#endif /* ${formats_last} */"
|
|
fi
|
|
|
|
# open the new #if:
|
|
#
|
|
echo ""
|
|
echo "#if ${formats}"
|
|
formats_last=${formats}
|
|
fi
|
|
|
|
# compute this value:
|
|
#
|
|
echo ""
|
|
echo " /* ${radix}^${sign}${exponent}: */"
|
|
exponent_remaining=${exponent}
|
|
value=1
|
|
while test ${exponent_remaining} != 0; do
|
|
if test `expr ${exponent_remaining} \>= ${exponent_x}` = 1; then
|
|
value="(${value} ${combine} ((${builtin_type}) ((tme_uint32_t) ${x})))"
|
|
exponent_remaining=`expr ${exponent_remaining} - ${exponent_x}`
|
|
else
|
|
x=`expr ${x} / ${radix}`
|
|
exponent_x=`expr ${exponent_x} - 1`
|
|
fi
|
|
done
|
|
echo " ${value},"
|
|
|
|
# double the exponent:
|
|
#
|
|
exponent=`expr ${exponent} \* 2`
|
|
done
|
|
|
|
# close any #if:
|
|
#
|
|
if test "x${formats_last}" != x; then
|
|
echo ""
|
|
echo "#endif /* ${formats_last} */"
|
|
fi
|
|
|
|
echo "};"
|
|
done
|
|
|
|
cat <<EOF
|
|
|
|
/* this returns the radix ${radix} mantissa and exponent of an in-range ${builtin_type}.
|
|
the mantissa is either zero, or in the range [1,${radix}): */
|
|
${builtin_type}
|
|
tme_float_radix${radix}_mantissa_exponent_${_builtin_type}(${builtin_type} value, tme_int32_t *_exponent)
|
|
{
|
|
tme_int32_t exponent;
|
|
tme_uint32_t exponent_bit;
|
|
int negate;
|
|
|
|
/* start with an exponent of zero: */
|
|
exponent = 0;
|
|
|
|
/* if the value is positive or negative zero, return the value: */
|
|
if (value == 0.0
|
|
|| -value == 0.0) {
|
|
*_exponent = exponent;
|
|
return (value);
|
|
}
|
|
|
|
/* take the magnitude of the value, but remember if it was negative: */
|
|
negate = (value < 0);
|
|
if (negate) {
|
|
value = 0 - value;
|
|
}
|
|
|
|
/* while the value is less than one: */
|
|
exponent_bit = TME_ARRAY_ELS(_tme_float_radix${radix}_exponent_bits_${_builtin_type}_neg) - 1;
|
|
for (; value < 1; ) {
|
|
|
|
/* if value is less than or equal to ${radix}^-(2^exponent_bit),
|
|
divide value by ${radix}^-(2^exponent_bit), and subtract 2^exponent_bit
|
|
from exponent: */
|
|
if (value <= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_neg[exponent_bit]
|
|
|| exponent_bit == 0) {
|
|
value /= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_neg[exponent_bit];
|
|
exponent -= (1 << exponent_bit);
|
|
}
|
|
|
|
/* otherwise, move to the next exponent bit: */
|
|
else {
|
|
exponent_bit--;
|
|
}
|
|
}
|
|
|
|
/* while the value is greater than or equal to ${radix}: */
|
|
exponent_bit = TME_ARRAY_ELS(_tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos) - 1;
|
|
for (; value >= ${radix}; ) {
|
|
|
|
/* if value is greater than or equal to ${radix}^(2^exponent_bit),
|
|
divide value by ${radix}^(2^exponent_bit), and add 2^exponent_bit
|
|
to exponent: */
|
|
if (value >= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos[exponent_bit]
|
|
|| exponent_bit == 0) {
|
|
value /= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos[exponent_bit];
|
|
exponent += (1 << exponent_bit);
|
|
}
|
|
|
|
/* otherwise, move to the next exponent bit: */
|
|
else {
|
|
exponent_bit--;
|
|
}
|
|
}
|
|
|
|
/* done: */
|
|
*_exponent = exponent;
|
|
return (negate ? 0 - value : value);
|
|
}
|
|
|
|
/* this scales a value by adding n to its exponent: */
|
|
${builtin_type}
|
|
tme_float_radix${radix}_scale_${_builtin_type}(${builtin_type} value, tme_int32_t _n)
|
|
{
|
|
tme_uint32_t exponent_bit, exponent;
|
|
tme_uint32_t n;
|
|
|
|
/* start with the most significant exponent bit: */
|
|
exponent_bit = TME_ARRAY_ELS(_tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos) - 1;
|
|
exponent = (1 << exponent_bit);
|
|
|
|
/* if n is negative: */
|
|
if (_n < 0) {
|
|
|
|
for (n = 0 - _n; n > 0;) {
|
|
if (n >= exponent || exponent == 1) {
|
|
value /= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos[exponent_bit];
|
|
n -= exponent;
|
|
}
|
|
else {
|
|
exponent >>= 1;
|
|
exponent_bit--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* otherwise, n is positive: */
|
|
else {
|
|
for (n = _n; n > 0;) {
|
|
if (n >= exponent || exponent == 1) {
|
|
value *= _tme_float_radix${radix}_exponent_bits_${_builtin_type}_pos[exponent_bit];
|
|
n -= exponent;
|
|
}
|
|
else {
|
|
exponent >>= 1;
|
|
exponent_bit--;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (value);
|
|
}
|
|
EOF
|
|
done
|
|
|
|
# dispatch on the type to close any protection:
|
|
#
|
|
case ${_builtin_type} in
|
|
long_double)
|
|
echo ; echo "#endif /* _TME_HAVE_${_BUILTIN_TYPE} */" ;;
|
|
*) ;;
|
|
esac
|
|
|
|
done
|
|
|
|
# done:
|
|
#
|
|
exit 0
|