diff options
Diffstat (limited to 'private/windbg/lib/intrncvt.c')
-rw-r--r-- | private/windbg/lib/intrncvt.c | 703 |
1 files changed, 703 insertions, 0 deletions
diff --git a/private/windbg/lib/intrncvt.c b/private/windbg/lib/intrncvt.c new file mode 100644 index 000000000..9ce055ffb --- /dev/null +++ b/private/windbg/lib/intrncvt.c @@ -0,0 +1,703 @@ +/*** +* intrncvt.c - internal floating point conversions +* +* Copyright (c) 1992-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* All fp string conversion routines use the same core conversion code +* that converts strings into an internal long double representation +* with an 80-bit mantissa field. The mantissa is represented +* as an array (man) of 32-bit unsigned longs, with man[0] holding +* the high order 32 bits of the mantissa. The binary point is assumed +* to be between the MSB and MSB-1 of man[0]. +* +* Bits are counted as follows: +* +* +* +-- binary point +* | +* v MSB LSB +* ---------------- ------------------ -------------------- +* |0 1 .... 31| | 32 33 ... 63| | 64 65 ... 95| +* ---------------- ------------------ -------------------- +* +* man[0] man[1] man[2] +* +* This file provides the final conversion routines from this internal +* form to the single, double, or long double precision floating point +* format. +* +* All these functions do not handle NaNs (it is not necessary) +* +* +*Revision History: +* 04-29-92 GDP written +* 05-26-92 GWK Windbg srcs +* +*******************************************************************************/ + + +#include <assert.h> +#include "cv.h" + + + + +#define INTRNMAN_LEN 3 /* internal mantissa length in int's */ + +// +// internal mantissaa representation +// for string conversion routines +// + +typedef u_long *intrnman; + + +typedef struct { + int max_exp; // maximum base 2 exponent (reserved for special values) + int min_exp; // minimum base 2 exponent (reserved for denormals) + int precision; // bits of precision carried in the mantissa + int exp_width; // number of bits for exponent + int format_width; // format width in bits + int bias; // exponent bias +} FpFormatDescriptor; + + + +static FpFormatDescriptor +DoubleFormat = { + 0x7ff - 0x3ff, // 1024, maximum base 2 exponent (reserved for special values) + 0x0 - 0x3ff, // -1023, minimum base 2 exponent (reserved for denormals) + 53, // bits of precision carried in the mantissa + 11, // number of bits for exponent + 64, // format width in bits + 0x3ff, // exponent bias +}; + +static FpFormatDescriptor +FloatFormat = { + 0xff - 0x7f, // 128, maximum base 2 exponent (reserved for special values) + 0x0 - 0x7f, // -127, minimum base 2 exponent (reserved for denormals) + 24, // bits of precision carried in the mantissa + 8, // number of bits for exponent + 32, // format width in bits + 0x7f, // exponent bias +}; + + + +// +// function prototypes +// + +int _RoundMan (intrnman man, int nbit); +int _ZeroTail (intrnman man, int nbit); +int _IncMan (intrnman man, int nbit); +void _CopyMan (intrnman dest, intrnman src); +void _CopyMan (intrnman dest, intrnman src); +void _FillZeroMan(intrnman man); +void _Shrman (intrnman man, int n); + +INTRNCVT_STATUS _ld12cvt(_ULDBL12 *pld12, void *d, FpFormatDescriptor *format); + +/*** +* _ZeroTail - check if a mantissa ends in 0's +* +*Purpose: +* Return TRUE if all mantissa bits after nbit (including nbit) are 0, +* otherwise return FALSE +* +* +*Entry: +* man: mantissa +* nbit: order of bit where the tail begins +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ +int _ZeroTail (intrnman man, int nbit) +{ + int nl = nbit / 32; + int nb = 31 - nbit % 32; + + + // + // |<---- tail to be checked ---> + // + // -- ------------------------ ---- + // |... | | ... | + // -- ------------------------ ---- + // ^ ^ ^ + // | | |<----nb-----> + // man nl nbit + // + + + + u_long bitmask = ~(MAX_ULONG << nb); + + if (man[nl] & bitmask) + return 0; + + nl++; + + for (;nl < INTRNMAN_LEN; nl++) + if (man[nl]) + return 0; + + return 1; +} + + + + +/*** +* _IncMan - increment mantissa +* +*Purpose: +* +* +*Entry: +* man: mantissa in internal long form +* nbit: order of bit that specifies the end of the part to be incremented +* +*Exit: +* returns 1 on overflow, 0 otherwise +* +*Exceptions: +* +*******************************************************************************/ + +int _IncMan (intrnman man, int nbit) +{ + int nl = nbit / 32; + int nb = 31 - nbit % 32; + + // + // |<--- part to be incremented -->| + // + // -- --------------------------- ---- + // |... | | ... | + // -- --------------------------- ---- + // ^ ^ ^ + // | | |<--nb--> + // man nl nbit + // + + u_long one = (u_long) 1 << nb; + int carry; + + carry = __addl(man[nl], one, &man[nl]); + + nl--; + + for (; nl >= 0 && carry; nl--) { + carry = (u_long) __addl(man[nl], (u_long) 1, &man[nl]); + } + + return carry; +} + + + + +/*** +* _RoundMan - round mantissa +* +*Purpose: +* round mantissa to nbit precision +* +* +*Entry: +* man: mantissa in internal form +* precision: number of bits to be kept after rounding +* +*Exit: +* returns 1 on overflow, 0 otherwise +* +*Exceptions: +* +*******************************************************************************/ + +int _RoundMan (intrnman man, int precision) +{ + int i,rndbit,nl,nb; + u_long rndmask; + int nbit; + int retval = 0; + + // + // The order of the n'th bit is n-1, since the first bit is bit 0 + // therefore decrement precision to get the order of the last bit + // to be kept + // + nbit = precision - 1; + + rndbit = nbit+1; + + nl = rndbit / 32; + nb = 31 - rndbit % 32; + + // + // Get value of round bit + // + + rndmask = (u_long)1 << nb; + + if ((man[nl] & rndmask) && + !_ZeroTail(man, rndbit+1)) { + + // + // round up + // + + retval = _IncMan(man, nbit); + } + + + // + // fill rest of mantissa with zeroes + // + + man[nl] &= MAX_ULONG << nb; + for(i=nl+1; i<INTRNMAN_LEN; i++) { + man[i] = (u_long)0; + } + + return retval; +} + + +/*** +* _CopyMan - copy mantissa +* +*Purpose: +* copy src to dest +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ +void _CopyMan (intrnman dest, intrnman src) +{ + u_long *p, *q; + int i; + + p = src; + q = dest; + + for (i=0; i < INTRNMAN_LEN; i++) { + *q++ = *p++; + } +} + + + +/*** +* _FillZeroMan - fill mantissa with zeroes +* +*Purpose: +* +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ +void _FillZeroMan(intrnman man) +{ + int i; + for (i=0; i < INTRNMAN_LEN; i++) + man[i] = (u_long)0; +} + + + +/*** +* _IsZeroMan - check if mantissa is zero +* +*Purpose: +* +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ +int _IsZeroMan(intrnman man) +{ + int i; + for (i=0; i < INTRNMAN_LEN; i++) + if (man[i]) + return 0; + + return 1; +} + + + + + +/*** +* _ShrMan - shift mantissa to the right +* +*Purpose: +* shift man by n bits to the right +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ +void _ShrMan (intrnman man, int n) +{ + int i, n1, n2, mask; + int carry_from_left; + + // + // declare this as volatile in order to work around a C8 + // optimization bug + // + + volatile int carry_to_right; + + n1 = n / 32; + n2 = n % 32; + + mask = ~(MAX_ULONG << n2); + + + // + // first deal with shifts by less than 32 bits + // + + carry_from_left = 0; + for (i=0; i<INTRNMAN_LEN; i++) { + + carry_to_right = man[i] & mask; + + man[i] >>= n2; + + man[i] |= carry_from_left; + + carry_from_left = carry_to_right << (32 - n2); + } + + + // + // now shift whole 32-bit ints + // + + for (i=INTRNMAN_LEN-1; i>=0; i--) { + if (i >= n1) { + man[i] = man[i-n1]; + } + else { + man[i] = 0; + } + } +} + + + + +/*** +* _ld12tocvt - _ULDBL12 floating point conversion +* +*Purpose: +* convert a internal _LBL12 structure into an IEEE floating point +* representation +* +* +*Entry: +* pld12: pointer to the _ULDBL12 +* format: pointer to the format descriptor structure +* +*Exit: +* *d contains the IEEE representation +* returns the INTRNCVT_STATUS +* +*Exceptions: +* +*******************************************************************************/ +INTRNCVT_STATUS _ld12cvt(_ULDBL12 *pld12, void *d, FpFormatDescriptor *format) +{ + u_long man[INTRNMAN_LEN]; + u_long saved_man[INTRNMAN_LEN]; + u_long msw; + unsigned int bexp; // biased exponent + int exp_shift; + int exponent, sign; + INTRNCVT_STATUS retval; + + exponent = (*U_EXP_12(pld12) & 0x7fff) - 0x3fff; // unbias exponent + sign = *U_EXP_12(pld12) & 0x8000; + + // + // bexp is the final biased value of the exponent to be used + // Each of the following blocks should provide appropriate + // values for man, bexp and retval. The mantissa is also + // shifted to the right, leaving space for the exponent + // and sign to be inserted + // + + + if (exponent == 0 - 0x3fff) { + + // either a denormal or zero + bexp = 0; + + if (_IsZeroMan(man)) { + + retval = INTRNCVT_OK; + } + else { + + _FillZeroMan(man); + + // denormal has been flushed to zero + + retval = INTRNCVT_UNDERFLOW; + } + } + else { + + man[0] = *UL_MANHI_12(pld12); + man[1] = *UL_MANLO_12(pld12); + man[2] = *U_XT_12(pld12) << 16; + + // save mantissa in case it needs to be rounded again + // at a different point (e.g., if the result is a denormal) + + _CopyMan(saved_man, man); + + if (_RoundMan(man, format->precision)) { + exponent ++; + } + + if (exponent < format->min_exp - format->precision ) { + + // + // underflow that produces a zero + // + + _FillZeroMan(man); + bexp = 0; + retval = INTRNCVT_UNDERFLOW; + } + + else if (exponent <= format->min_exp) { + + // + // underflow that produces a denormal + // + // + + // The (unbiased) exponent will be MIN_EXP + // Find out how much the mantissa should be shifted + // One shift is done implicitly by moving the + // binary point one bit to the left, i.e., + // we treat the mantissa as .ddddd instead of d.dddd + // (where d is a binary digit) + + int shift = format->min_exp - exponent; + + // The mantissa should be rounded again, so it + // has to be restored + + _CopyMan(man,saved_man); + + _ShrMan(man, shift); + _RoundMan(man, format->precision); // need not check for carry + + // make room for the exponent + sign + + _ShrMan(man, format->exp_width + 1); + + bexp = 0; + retval = INTRNCVT_UNDERFLOW; + + } + + else if (exponent >= format->max_exp) { + + // + // overflow, return infinity + // + + _FillZeroMan(man); + man[0] |= (1 << 31); // set MSB + + // make room for the exponent + sign + + _ShrMan(man, (format->exp_width + 1) - 1); + + bexp = format->max_exp + format->bias; + + retval = INTRNCVT_OVERFLOW; + } + + else { + + // + // valid, normalized result + // + + bexp = exponent + format->bias; + + + // clear implied bit + + man[0] &= (~( 1 << 31)); + + // + // shift right to make room for exponent + sign + // + + _ShrMan(man, (format->exp_width + 1) - 1); + + retval = INTRNCVT_OK; + + } + } + + + exp_shift = 32 - (format->exp_width + 1); + msw = man[0] | + (bexp << exp_shift) | + (sign ? 1<<31 : 0); + + if (format->format_width == 64) { + + *UL_HI_D(d) = msw; + *UL_LO_D(d) = man[1]; + } + + else if (format->format_width == 32) { + + *(u_long *)d = msw; + + } + + return retval; +} + + +/*** +* _ld12tod - convert _ULDBL12 to double +* +*Purpose: +* +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ +INTRNCVT_STATUS _ld12tod(_ULDBL12 *pld12, UDOUBLE *d) +{ + return _ld12cvt(pld12, d, &DoubleFormat); +} + + + +/*** +* _ld12tof - convert _ULDBL12 to float +* +*Purpose: +* +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ +INTRNCVT_STATUS _ld12tof(_ULDBL12 *pld12, FLOAT *f) +{ + return _ld12cvt(pld12, f, &FloatFormat); +} + + +/*** +* _ld12told - convert _ULDBL12 to 80 bit long double +* +*Purpose: +* +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ +void _ld12told(_ULDBL12 *pld12, _ULDOUBLE *pld) +{ + + // + // This implementation is based on the fact that the _ULDBL12 format is + // identical to the long double and has 2 extra bytes of mantissa + // + + u_short exp, sign; + u_long man[INTRNMAN_LEN]; + + exp = *U_EXP_12(pld12) & (u_short)0x7fff; + sign = *U_EXP_12(pld12) & (u_short)0x8000; + + man[0] = *UL_MANHI_12(pld12); + man[1] = *UL_MANLO_12(pld12); + man[2] = *U_XT_12(pld12) << 16; + + if (_RoundMan(man, 64)) + exp ++; + + *UL_MANHI_LD(pld) = man[0]; + *UL_MANLO_LD(pld) = man[1]; + *U_EXP_LD(pld) = sign | exp; +} + + +void _atodbl(UDOUBLE *d, char *str) +{ + char *EndPtr; + _ULDBL12 ld12; + + __strgtold12(&ld12, &EndPtr, str, 0 ); + _ld12tod(&ld12, d); +} + + +void _atoldbl(_ULDOUBLE *ld, char *str) +{ + char *EndPtr; + _ULDBL12 ld12; + + __strgtold12(&ld12, &EndPtr, str, 0 ); + _ld12told(&ld12, ld); +} + + +void _atoflt(FLOAT *f, char *str) +{ + char *EndPtr; + _ULDBL12 ld12; + + __strgtold12(&ld12, &EndPtr, str, 0 ); + _ld12tof(&ld12, f); +} |