X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fdecimal.c;h=6524443eab3d57168325a710d2ac93e05d74671a;hb=e6d98ba2612414fbd67e463442e17de88d868cb1;hp=daeac6e6c14034b2604e6b523dae46ff89c5e923;hpb=e842469902a503885bdfe2b961a7ce41a20f48ac;p=mono.git diff --git a/mono/metadata/decimal.c b/mono/metadata/decimal.c index daeac6e6c14..6524443eab3 100644 --- a/mono/metadata/decimal.c +++ b/mono/metadata/decimal.c @@ -1,12 +1,12 @@ /* - decimal.c - - conversions and numerical operations for the c# type System.Decimal - - Author: Martin Weindel (martin.weindel@t-online.de) - - (C) 2001 by Martin Weindel -*/ + * decimal.c + * + * conversions and numerical operations for the c# type System.Decimal + * + * Author: Martin Weindel (martin.weindel@t-online.de) + * + * (C) 2001 by Martin Weindel + */ /* * machine dependent configuration for @@ -22,6 +22,9 @@ #ifdef HAVE_MEMORY_H #include #endif +#ifdef _MSC_VER +#include +#endif #ifndef DISABLE_DECIMAL @@ -565,41 +568,35 @@ my_g_bit_nth_msf (gsize mask) __asm__("bsrq %1,%0\n\t" : "=r" (r) : "rm" (mask)); return r; +#elif defined(__i386__) && defined(_MSC_VER) + unsigned long bIndex = 0; + if (_BitScanReverse (&bIndex, mask)) + return bIndex; + return -1; +#elif defined(__x86_64__) && defined(_MSC_VER) + unsigned long bIndex = 0; + if (_BitScanReverse64 (&bIndex, mask)) + return bIndex; + return -1; #else - return g_bit_nth_msf (mask, sizeof (gsize) * 8); + int i; + + i = sizeof (gsize) * 8; + while (i > 0) { + i --; + if (mask & (1UL << i)) + return i; + } + return -1; #endif } /* returns log2(a) or DECIMAL_LOG_NEGINF for a = 0 */ DECINLINE static int log2_32(guint32 a) { - int tlog2 = 0; - if (a == 0) return DECIMAL_LOG_NEGINF; - if ((a >> 16) != 0) { - a >>= 16; - tlog2 += 16; - } - if ((a >> 8) != 0) { - a >>= 8; - tlog2 += 8; - } - if ((a >> 4) != 0) { - a >>= 4; - tlog2 += 4; - } - if ((a >> 2) != 0) { - a >>= 2; - tlog2 += 2; - } - if ((a >> 1) != 0) { - a >>= 1; - tlog2 += 1; - } - tlog2 += (int) a; - - return tlog2; + return my_g_bit_nth_msf (a) + 1; } /* returns log2(a) or DECIMAL_LOG_NEGINF for a = 0 */ @@ -683,7 +680,7 @@ DECINLINE static int adjustScale128(guint64* palo, guint64* pahi, int deltaScale DECINLINE static int rescale128(guint64* pclo, guint64* pchi, int* pScale, int texp, int minScale, int maxScale, int roundFlag) { - guint32 factor, overhang, prev_lo; + guint32 factor, overhang; int scale, i, rc, roundBit = 0; PRECONDITION(texp >= 0); @@ -694,15 +691,38 @@ DECINLINE static int rescale128(guint64* pclo, guint64* pchi, int* pScale, int t /* reduce exp */ while (texp > 0 && scale <= maxScale) { overhang = (guint32)(*pchi >> 32); - prev_lo = *pclo; + + /* The original loop was this: */ + /* + while (texp > 0 && (overhang > (2<> 32); + } + */ + if (overhang > 0) { + int msf = my_g_bit_nth_msf (overhang); + int shift = msf - (DECIMAL_MAX_INTFACTORS + 2); + + if (shift >= texp) + shift = texp - 1; + + if (shift > 0) { + texp -= shift; + *pclo = (*pclo >> shift) | ((*pchi & ((1 << shift) - 1)) << (64 - shift)); + *pchi >>= shift; + overhang >>= shift; + + g_assert (texp > 0); + g_assert (overhang > (2 << DECIMAL_MAX_INTFACTORS)); + } + } while (texp > 0 && (overhang > (2<>= 1; } - if (texp == 0) - roundBit = (int)(prev_lo & 1); if (texp > DECIMAL_MAX_INTFACTORS) i = DECIMAL_MAX_INTFACTORS; else i = texp; @@ -1412,6 +1432,16 @@ gint32 mono_decimalDiv(/*[Out]*/decimal_repr* pC, /*[In]*/decimal_repr* pA, /*[I MONO_ARCH_SAVE_REGS; + /* Check for common cases */ + if (mono_decimalCompare (pA, pB) == 0) + /* One */ + return pack128toDecimal (pC, 1, 0, 0, 0); + pA->signscale.sign = pA->signscale.sign ? 0 : 1; + if (mono_decimalCompare (pA, pB) == 0) + /* Minus one */ + return pack128toDecimal (pC, 1, 0, 0, 1); + pA->signscale.sign = pA->signscale.sign ? 0 : 1; + rc = decimalDivSub(pA, pB, &clo, &chi, &texp); if (rc != DECIMAL_SUCCESS) { if (rc == DECIMAL_FINISHED) rc = DECIMAL_SUCCESS;