Commit 86b5e05a authored by Matthias Heil's avatar Matthias Heil
Browse files

Commit of new floating point module

[r1630]
parent b623f4fc
......@@ -14,13 +14,13 @@ INSTALL_HEADERS = tv.h
SOURCES = $(INSTALL_HEADERS)
SOURCES += Makefile.in tv.c tv_t.h strcalc.c strcalc.h fltcalc.c fltcalc.h ieee754.h
SOURCES += Makefile.in tv.c tv_t.h strcalc.c strcalc.h fltcalc.c fltcalc.h
include $(topdir)/MakeRules
CPPFLAGS += -I$(top_srcdir)/ir/common -I$(top_srcdir)/ir/tr -I$(top_srcdir)/ir/adt \
-I$(top_srcdir)/ir/ident -I$(top_srcdir)/ir/ir -I$(top_srcdir)/ir/debug \
-I$(top_srcdir)/ir/st -I$(top_srcdir)/ir/ana
-I$(top_srcdir)/ir/st -I$(top_srcdir)/ir/ana \
include $(top_srcdir)/MakeTargets
......
This diff is collapsed.
#ifndef _FLTCALC_H_
#define _FLTCALC_H_
#ifdef USE_LONG_DOUBLE
#ifdef HAVE_LONG_DOUBLE
typedef long double LLDBL;
#else
typedef double LLDBL;
#endif
typedef enum {
FC_add, /**< addition */
FC_sub, /**< subtraction */
FC_mul, /**< multiplication */
FC_div, /**< divide */
FC_neg, /**< negate */
FC_int, /**< truncate to integer */
FC_rnd, /**< round to integer */
} fc_op_t;
enum {
FC_ADD,
FC_SUB,
FC_MUL,
FC_DIV,
FC_NEG
FC_DEC,
FC_HEX,
FC_BIN,
};
#define fc_add(a, b) fc_calc((a), (b), FC_ADD)
#define fc_sub(a, b) fc_calc((a), (b), FC_SUB)
#define fc_mul(a, b) fc_calc((a), (b), FC_MUL)
#define fc_div(a, b) fc_calc((a), (b), FC_DIV)
#define fc_neg(a) fc_calc((a), NULL, FC_NEG)
/* rounding modes */
typedef enum {
FC_TONEAREST,
FC_TOPOSITIVE,
FC_TONEGATIVE,
FC_TOZERO,
} fc_rounding_mode_t;
#define FC_DEFAULT_PRECISION 64
#define FC_DECLARE1(code) char* fc_##code(const void *a, void *result)
#define FC_DECLARE2(code) char* fc_##code(const void *a, const void *b, void *result)
/*@{*/
/** internal buffer access
* All functions that accept NULL as return buffer put their result into an
* internal buffer.
* @return fc_get_buffer() returns the pointer to the buffer, fc_get_buffer_length()
* returns the size of this buffer
*/
const void *fc_get_buffer(void);
const int fc_get_buffer_length(void);
/*}@*/
void fc_val_from_str(const char *str, unsigned int len);
void fc_val_from_float(LLDBL l);
char* fc_val_from_str(const char *str, unsigned int len, char exp_size, char mant_size, char *result);
/** get the representation of a floating point value
* This function tries to builds a representation having the same value as the
* float number passed.
* If the wished precision is less than the precicion of LLDBL the value built
* will be rounded. Therefore only an approximation of the passed float can be
* expected in this case.
*
* @param l The floating point number to build a representation for
* @param exp_size The number of bits of the new exponent
* @param mant_size The number of bits of the new mantissa
* @param result A buffer to hold the value built. If this is NULL, the internal
* accumulator buffer is used. Note that the buffer must be big
* enough to hold the value. Use fc_get_buffer_length() to find out
* the size needed
* @return The result pointer passed to the function. If this was NULL this returns
* a pointer to the internal accumulator buffer
*/
char* fc_val_from_float(LLDBL l, char exp_size, char mant_size, char *result);
/** retrieve the float value of an internal value
* This function casts the internal value to LLDBL and returns a LLDBL with
* that value.
* This implies that values of higher precision than LLDBL are subject to
* rounding, so the returned value might not the same than the actually
* represented value.
*
* @param val The representation of a float value
* @return a float value approximating the represented value
*/
LLDBL fc_val_to_float(const void *val);
void fc_get_min(unsigned int num_bits);
void fc_get_max(unsigned int num_bits);
void fc_get_nan(void);
void fc_get_inf(void);
/** cast a value to another precision
* This function changes the precision of a float representation.
* If the new precision is less than the original precision the returned
* value might not be the same as the original value.
*
* @param val The value to be casted
* @param exp_size The number of bits of the new exponent
* @param mant_size The number of bits of the new mantissa
* @param result A buffer to hold the value built. If this is NULL, the internal
* accumulator buffer is used. Note that the buffer must be big
* enough to hold the value. Use fc_get_buffer_length() to find out
* the size needed
* @return The result pointer passed to the function. If this was NULL this returns
* a pointer to the internal accumulator buffer
*/
char* fc_cast(const void *val, char exp_size, char mant_size, char *result);
/*@{*/
/** build a special float value
* This function builds a representation for a special float value, as indicated by the
* function's suffix.
*
* @param exponent_size The number of bits of exponent of the float type the value
* is created for
* @param mantissa_size The number of bits of mantissa of the float type the value
* is created for
* @param result A buffer to hold the value built. If this is NULL, the internal
* accumulator buffer is used. Note that the buffer must be big
* enough to hold the value. Use fc_get_buffer_length() to find out
* the size needed
* @return The result pointer passed to the function. If this was NULL this returns
* a pointer to the internal accumulator buffer
*/
char* fc_get_min(unsigned int exponent_size, unsigned int mantissa_size, char* result);
char* fc_get_max(unsigned int exponent_size, unsigned int mantissa_size, char* result);
char* fc_get_snan(unsigned int exponent_size, unsigned int mantissa_size, char* result);
char* fc_get_qnan(unsigned int exponent_size, unsigned int mantissa_size, char* result);
char* fc_get_plusinf(unsigned int exponent_size, unsigned int mantissa_size, char* result);
char* fc_get_minusinf(unsigned int exponent_size, unsigned int mantissa_size, char* result);
/*}@*/
void fc_calc(const void *a, const void *b, int opcode);
char *fc_print_dec(const void *a, char *buf, int buflen);
int fc_is_zero(const void *a);
int fc_is_negative(const void *a);
int fc_is_inf(const void *a);
int fc_is_nan(const void *a);
int fc_is_subnormal(const void *a);
FC_DECLARE2(add);
FC_DECLARE2(sub);
FC_DECLARE2(mul);
FC_DECLARE2(div);
FC_DECLARE1(neg);
FC_DECLARE1(int);
FC_DECLARE1(rnd);
char *fc_print(const void *a, char *buf, int buflen, unsigned base);
/** Compare two values
* This function compares two values
*
* @param a Value No. 1
* @param b Value No. 2
* @result The returned value will be one of
* -1 if a < b
* 0 if a == b
* 1 if a > b
* 2 if either value is NaN
*/
int fc_comp(const void *a, const void *b);
/** Set new rounding mode
* This function sets the rounding mode to one of the following, returning
* the previously set rounding mode.
* FC_TONEAREST (default):
* Any unrepresentable value is rounded to the nearest representable
* value. If it lies in the middle the value with the least significant
* bit of zero is chosen.
* Values too big to represent will round to +-infinity.
* FC_TONEGATIVE
* Any unrepresentable value is rounded towards negative infinity.
* Positive values too big to represent will round to the biggest
* representable value, negative values too small to represent will
* round to -infinity.
* FC_TOPOSITIVE
* Any unrepresentable value is rounded towards positive infinity
* Negative values too small to represent will round to the biggest
* representable value, positive values too big to represent will
* round to +infinity.
* FC_TOZERO
* Any unrepresentable value is rounded towards zero, effectively
* chopping off any bits beyond the mantissa size.
* Values too big to represent will round to the biggest/smallest
* representable value.
*
* These modes correspond to the modes required by the ieee standard.
*
* @param mode The new rounding mode. Any value other than the four
* defined values will have no effect.
* @return The previous rounding mode.
*
* @see fc_get_rounding_mode()
* @see IEEE754, IEEE854 Floating Point Standard
*/
fc_rounding_mode_t fc_set_rounding_mode(fc_rounding_mode_t mode);
/** Get the rounding mode
* This function retrieves the currently used rounding mode
*
* @return The current rounding mode
* @see fc_set_rounding_mode()
*/
fc_rounding_mode_t fc_get_rounding_mode(void);
/** Get bit representation of a value
* This function allows to read a value in encoded form, bytewise.
* The value will be packed corresponding to the way used by the ieee
* encoding formats, i.e.
* One bit sign
* exp_size bits exponent + bias
* mant_size bits mantissa, without leading 1
*
* As in ieee, an exponent of 0 indicates a denormalized number, which
* implies a most significant bit of zero instead of one; an exponent
* of all ones (2**exp_size - 1) encodes infinity if the mantissa is
* all zeroes, else Not A Number.
*
* @param val A pointer to the value. If NULL is passed a copy of the
* most recent value passed to this function is used, saving the
* packing step. This behaviour may be changed in the future.
* @param num_bit The maximum number of bits to return. Any bit beyond
* num_bit will be returned as zero.
* @param byte_ofs The byte index to read, 0 is the least significant
* byte.
* @return 8 bits of encoded data
*/
unsigned char fc_sub_bits(const void *val, unsigned num_bit, unsigned byte_ofs);
void init_fltcalc(int precision);
#endif /* _FLTCALC_H_ */
/* Copyright (C) 1992, 1995, 1996, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _IEEE754_H
#define _IEEE754_H 1
#include <features.h>
#include <endian.h>
__BEGIN_DECLS
union ieee754_float
{
float f;
/* This is the IEEE 754 single-precision format. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:8;
unsigned int mantissa:23;
#endif /* Big endian. */
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int mantissa:23;
unsigned int exponent:8;
unsigned int negative:1;
#endif /* Little endian. */
} ieee;
/* This format makes it easier to see if a NaN is a signalling NaN. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:8;
unsigned int quiet_nan:1;
unsigned int mantissa:22;
#endif /* Big endian. */
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int mantissa:22;
unsigned int quiet_nan:1;
unsigned int exponent:8;
unsigned int negative:1;
#endif /* Little endian. */
} ieee_nan;
};
#define IEEE754_FLOAT_BIAS 0x7f /* Added to exponent. */
union ieee754_double
{
double d;
/* This is the IEEE 754 double-precision format. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:11;
/* Together these comprise the mantissa. */
unsigned int mantissa0:20;
unsigned int mantissa1:32;
#endif /* Big endian. */
#if __BYTE_ORDER == __LITTLE_ENDIAN
# if __FLOAT_WORD_ORDER == BIG_ENDIAN
unsigned int mantissa0:20;
unsigned int exponent:11;
unsigned int negative:1;
unsigned int mantissa1:32;
# else
/* Together these comprise the mantissa. */
unsigned int mantissa1:32;
unsigned int mantissa0:20;
unsigned int exponent:11;
unsigned int negative:1;
# endif
#endif /* Little endian. */
} ieee;
/* This format makes it easier to see if a NaN is a signalling NaN. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:11;
unsigned int quiet_nan:1;
/* Together these comprise the mantissa. */
unsigned int mantissa0:19;
unsigned int mantissa1:32;
#else
# if __FLOAT_WORD_ORDER == BIG_ENDIAN
unsigned int mantissa0:19;
unsigned int quiet_nan:1;
unsigned int exponent:11;
unsigned int negative:1;
unsigned int mantissa1:32;
# else
/* Together these comprise the mantissa. */
unsigned int mantissa1:32;
unsigned int mantissa0:19;
unsigned int quiet_nan:1;
unsigned int exponent:11;
unsigned int negative:1;
# endif
#endif
} ieee_nan;
};
#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent. */
union ieee854_long_double
{
long double d;
/* This is the IEEE 854 double-extended-precision format. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:15;
unsigned int empty:16;
unsigned int mantissa0:32;
unsigned int mantissa1:32;
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
# if __FLOAT_WORD_ORDER == BIG_ENDIAN
unsigned int exponent:15;
unsigned int negative:1;
unsigned int empty:16;
unsigned int mantissa0:32;
unsigned int mantissa1:32;
# else
unsigned int mantissa1:32;
unsigned int mantissa0:32;
unsigned int exponent:15;
unsigned int negative:1;
unsigned int empty:16;
# endif
#endif
} ieee;
/* This is for NaNs in the IEEE 854 double-extended-precision format. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:15;
unsigned int empty:16;
unsigned int one:1;
unsigned int quiet_nan:1;
unsigned int mantissa0:30;
unsigned int mantissa1:32;
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
# if __FLOAT_WORD_ORDER == BIG_ENDIAN
unsigned int exponent:15;
unsigned int negative:1;
unsigned int empty:16;
unsigned int mantissa0:30;
unsigned int quiet_nan:1;
unsigned int one:1;
unsigned int mantissa1:32;
# else
unsigned int mantissa1:32;
unsigned int mantissa0:30;
unsigned int quiet_nan:1;
unsigned int one:1;
unsigned int exponent:15;
unsigned int negative:1;
unsigned int empty:16;
# endif
#endif
} ieee_nan;
};
#define IEEE854_LONG_DOUBLE_BIAS 0x3fff
__END_DECLS
#endif /* ieee754.h */
......@@ -17,14 +17,20 @@
/*
* local definitions and macros
*/
#define CLEAR_CALC_BUFFER() assert(calc_buffer); memset(calc_buffer, SC_0, CALC_BUFFER_SIZE)
#define CLEAR_BUFFER(b) assert(b); memset(b, SC_0, CALC_BUFFER_SIZE)
#define _val(a) ((a)-SC_0)
#define _digit(a) ((a)+SC_0)
#define _bitisset(digit, pos) (and_table[_val(digit)][_val(shift_table[pos])] != SC_0)
#define fail_char(a, b, c, d) _fail_char((a), (b), (c), (d), __FILE__, __LINE__)
#ifdef STRCALC_DEBUG_COMPUTATION
/* shortcut output for debugging */
# define sc_print_hex(a) sc_print((a), 0, SC_HEX)
# define sc_print_dec(a) sc_print((a), 0, SC_DEC)
# define sc_print_oct(a) sc_print((a), 0, SC_OCT)
# define sc_print_bin(a) sc_print((a), 0, SC_BIN)
#ifdef STRCALC_DEBUG_PRINTCOMP
# define DEBUGPRINTF_COMPUTATION(x) printf x
#else
# define DEBUGPRINTF_COMPUTATION(x) ((void)0)
......@@ -768,6 +774,9 @@ static void _shr(const char *val1, char *buffer, long offset, int radius, unsign
/* if shifting far enough the result is either 0 or -1 */
if (offset >= radius)
{
if (!sc_is_zero(val1)) {
carry_flag = 1;
}
memset(buffer, sign, CALC_BUFFER_SIZE);
return;
}
......@@ -775,18 +784,19 @@ static void _shr(const char *val1, char *buffer, long offset, int radius, unsign
shift = offset % 4;
offset = offset / 4;
/* check if any bits are lost, and set carry_flag is so */
/* check if any bits are lost, and set carry_flag if so */
for (counter = 0; counter < offset; counter++)
{
if (val1[counter] != carry_flag)
if (val1[counter] != 0)
{
carry_flag = 1;
break;
}
}
if ((carry_flag == 0) && (_val(val1[counter]) & shift) != 0)
if ((_val(val1[counter]) & ((1<<shift)-1)) != 0)
{
carry_flag = 1;
}
/* shift digits to the right with offset, carry and all */
counter = 0;
if (radius/4 - offset > 0) {
......@@ -861,7 +871,7 @@ const int sc_get_buffer_length(void)
}
/* XXX doesn't check for overflows */
void sc_val_from_str(const char *str, unsigned int len)
void sc_val_from_str(const char *str, unsigned int len, void *buffer)
{
const char *orig_str = str;
unsigned int orig_len = len;
......@@ -875,7 +885,9 @@ void sc_val_from_str(const char *str, unsigned int len)
/* a string no characters long is an error */
assert(len);
CLEAR_CALC_BUFFER();
if (buffer == NULL) buffer = calc_buffer;
CLEAR_BUFFER(buffer);
memset(base, SC_0, CALC_BUFFER_SIZE);
memset(val, SC_0, CALC_BUFFER_SIZE);
......@@ -1005,12 +1017,14 @@ void sc_val_from_str(const char *str, unsigned int len)
}
}
void sc_val_from_long(long value)
void sc_val_from_long(long value, void *buffer)
{
char *pos;
char sign, is_minlong;
pos = calc_buffer;
if (buffer == NULL) buffer = calc_buffer;
pos = buffer;
sign = (value < 0);
is_minlong = value == LONG_MIN;
......@@ -1022,18 +1036,34 @@ void sc_val_from_long(long value)
value = -value;
}
CLEAR_CALC_BUFFER();
CLEAR_BUFFER(buffer);
while ((value != 0) && (pos < calc_buffer + CALC_BUFFER_SIZE))
while ((value != 0) && (pos < (char*)buffer + CALC_BUFFER_SIZE))
{
*pos++ = _digit(value % 16);
value /= 16;
*pos++ = _digit(value & 0xf);
value >>= 4;
}
if (sign) {
if (is_minlong) _inc(calc_buffer, calc_buffer);
_negate(calc_buffer, calc_buffer);
if (is_minlong)
_inc(buffer, buffer);
_negate(buffer, buffer);
}
}
void sc_val_from_ulong(unsigned long value, void *buffer)
{
char *pos;
if (buffer == NULL) buffer = calc_buffer;
pos = buffer;
while (pos < (char*)buffer + CALC_BUFFER_SIZE)
{
*pos++ = _digit(value & 0xf);
value >>= 4;
}
}
......@@ -1049,15 +1079,17 @@ long sc_val_to_long(const void *val)
return l;
}
void sc_min_from_bits(unsigned int num_bits, unsigned int sign)
void sc_min_from_bits(unsigned int num_bits, unsigned int sign, void *buffer)
{
char* pos;
int i, bits;
CLEAR_CALC_BUFFER();
if (buffer == NULL) buffer = calc_buffer;
CLEAR_BUFFER(buffer);
if (!sign) return; /* unsigned means minimum is 0(zero) */
pos = calc_buffer;
pos = buffer;
bits = num_bits - 1;
for (i = 0; i < bits/4; i++)
......@@ -1069,13 +1101,14 @@ void sc_min_from_bits(unsigned int num_bits, unsigned int sign)
*pos++ = SC_F;
}
void sc_max_from_bits(unsigned int num_bits, unsigned int sign)
void sc_max_from_bits(unsigned int num_bits, unsigned int sign, void *buffer)
{
char* pos;
int i, bits;
CLEAR_CALC_BUFFER();
pos = calc_buffer;
if (buffer == NULL) buffer = calc_buffer;
CLEAR_BUFFER(buffer);
pos = buffer;
bits = num_bits - sign;
for (i = 0; i < bits/4; i++)
......@@ -1087,13 +1120,14 @@ void sc_max_from_bits(unsigned int num_bits, unsigned int sign)
*pos++ = SC_0;
}
void sc_calc(const void* value1, const void* value2, unsigned op)
void sc_calc(const void* value1, const void* value2, unsigned op, void *buffer)
{