Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / metadata / decimal-ms.c
index df64545d153dff86d1d3032b445410335ef2659e..c87eac6882d420f826ac1488cf0bf672cbd3df83 100644 (file)
@@ -1,16 +1,17 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-// Copyright 2015 Xamarin Inc
-//
-// File: decimal.c
-//
-// Ported from C++ to C and adjusted to Mono runtime
-//
-// Pending:
-//   DoToCurrency (they look like new methods we do not have)
-//
+/**
+ * \file
+ * Copyright (c) Microsoft. All rights reserved.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ *
+ * Copyright 2015 Xamarin Inc
+ *
+ * File: decimal.c
+ *
+ * Ported from C++ to C and adjusted to Mono runtime
+ *
+ * Pending:
+ *   DoToCurrency (they look like new methods we do not have)
+ */
 #ifndef DISABLE_DECIMAL
 #include "config.h"
 #include <stdint.h>
@@ -29,6 +30,7 @@
 #include <intrin.h>
 #endif
 #include "decimal-ms.h"
+#include "number-ms.h"
 
 #define min(a, b) (((a) < (b)) ? (a) : (b))
 
@@ -55,8 +57,13 @@ static const uint32_t ten_to_ten_div_4 = 2500000000U;
 #define DECIMAL_LO32(dec)        ((dec).v.v.Lo32)
 #define DECIMAL_MID32(dec)       ((dec).v.v.Mid32)
 #define DECIMAL_HI32(dec)        ((dec).Hi32)
-#define DECIMAL_LO64_GET(dec)    ((dec).v.Lo64)
-#define DECIMAL_LO64_SET(dec,value)   {(dec).v.Lo64 = value; }
+#if G_BYTE_ORDER != G_LITTLE_ENDIAN
+# define DECIMAL_LO64_GET(dec)   (((uint64_t)((dec).v.v.Mid32) << 32) | (dec).v.v.Lo32)
+# define DECIMAL_LO64_SET(dec,value)   {(dec).v.v.Lo32 = (value); (dec).v.v.Mid32 = ((value) >> 32); }
+#else
+# define DECIMAL_LO64_GET(dec)    ((dec).v.Lo64)
+# define DECIMAL_LO64_SET(dec,value)   {(dec).v.Lo64 = value; }
+#endif
 
 #define DECIMAL_SETZERO(dec) {DECIMAL_LO32(dec) = 0; DECIMAL_MID32(dec) = 0; DECIMAL_HI32(dec) = 0; DECIMAL_SIGNSCALE(dec) = 0;}
 #define COPYDEC(dest, src) {DECIMAL_SIGNSCALE(dest) = DECIMAL_SIGNSCALE(src); DECIMAL_HI32(dest) = DECIMAL_HI32(src); \
@@ -88,50 +95,8 @@ typedef union {
 } SPLIT64;
 
 static const SPLIT64    ten_to_eighteen = { 1000000000000000000ULL };
-// Double Bias
-#define DBLBIAS 1022
-
-// Structure to access an encoded double floating point
-typedef union{
-    struct {
-#if BYTE_ORDER == G_BIG_ENDIAN
-      unsigned int sign:1;
-      unsigned int exp:11;
-      unsigned int mantHi:20;
-      unsigned int mantLo;
-#else // BIGENDIAN
-      unsigned int mantLo;
-      unsigned int mantHi:20;
-      unsigned int exp:11;
-      unsigned int sign:1;
-#endif
-    } u;
-    double dbl;
-} DoubleStructure;
-
-#if BYTE_ORDER == G_BIG_ENDIAN
-#define DEFDS(Lo, Hi, exp, sign) { {sign, exp, Hi, Lo } }
-#else
-#define DEFDS(Lo, Hi, exp, sign) { {Lo, Hi, exp, sign} }
-#endif
-
-const DoubleStructure ds2to64 = DEFDS(0, 0, DBLBIAS + 65, 0);
 
-// Single floating point Bias
-#define SNGBIAS 126
-
-// Structure to access an encoded single floating point
-typedef struct {
-#if BYTE_ORDER == G_BIG_ENDIAN
-    unsigned int sign:1;
-    unsigned int exp:8;
-    unsigned int mant:23;
-#else
-    unsigned int mant:23;
-    unsigned int exp:8;
-    unsigned int sign:1;
-#endif
-} SingleStructure;
+const MonoDouble_double ds2to64 = { .s = { .sign = 0, .exp = MONO_DOUBLE_BIAS + 65, .mantHi = 0, .mantLo = 0 } };
 
 //
 // Data tables
@@ -688,7 +653,7 @@ ScaleResult(uint32_t *res, int hi_res, int scale)
 // Decimal multiply
 // Returns: MONO_DECIMAL_OVERFLOW or MONO_DECIMAL_OK
 static MonoDecimalStatus
-VarDecMul(MonoDecimal * left, MonoDecimal * right, MonoDecimal * result)
+mono_decimal_multiply_result(MonoDecimal * left, MonoDecimal * right, MonoDecimal * result)
 {
        SPLIT64 tmp;
        SPLIT64 tmp2;
@@ -1119,15 +1084,15 @@ RetDec:
 }
 
 // Decimal addition
-static MonoDecimalStatus
-VarDecAdd(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
+static MonoDecimalStatus G_GNUC_UNUSED
+mono_decimal_add(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
 {
     return DecAddSub (left, right, result, 0);
 }
 
 // Decimal subtraction
-static MonoDecimalStatus
-VarDecSub(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
+static MonoDecimalStatus G_GNUC_UNUSED
+mono_decimal_sub(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
 {
     return DecAddSub (left, right, result, DECIMAL_NEG);
 }
@@ -1368,9 +1333,9 @@ OverflowUnscale (uint32_t *quo, gboolean remainder)
        }
 }
 
-// VarDecDiv - Decimal divide
-static MonoDecimalStatus
-VarDecDiv(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
+// mono_decimal_divide - Decimal divide
+static MonoDecimalStatus G_GNUC_UNUSED
+mono_decimal_divide_result(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
 {
        uint32_t   quo[3];
        uint32_t   quoSave[3];
@@ -1714,26 +1679,25 @@ VarDecDiv(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
        return MONO_DECIMAL_OK;
 }
 
-// VarDecAbs - Decimal Absolute Value
-static void
-VarDecAbs (MonoDecimal *pdecOprd, MonoDecimal *result)
+// mono_decimal_absolute - Decimal Absolute Value
+static void G_GNUC_UNUSED
+mono_decimal_absolute (MonoDecimal *pdecOprd, MonoDecimal *result)
 {
        COPYDEC(*result, *pdecOprd);
        result->u.u.sign &= ~DECIMAL_NEG;
        // Microsoft does not set reserved here
 }
 
-// VarDecFix - Decimal Fix (chop to integer)
+// mono_decimal_fix - Decimal Fix (chop to integer)
 static void
-VarDecFix (MonoDecimal *pdecOprd, MonoDecimal *result)
+mono_decimal_fix (MonoDecimal *pdecOprd, MonoDecimal *result)
 {
        DecFixInt(result, pdecOprd);
 }
 
-
-// VarDecInt - Decimal Int (round down to integer)
+// mono_decimal_round_to_int - Decimal Int (round down to integer)
 static void
-VarDecInt (MonoDecimal *pdecOprd, MonoDecimal *result)
+mono_decimal_round_to_int (MonoDecimal *pdecOprd, MonoDecimal *result)
 {
        if (DecFixInt(result, pdecOprd) != 0 && (result->u.u.sign & DECIMAL_NEG)) {
                // We have chopped off a non-zero amount from a negative value.  Since
@@ -1748,10 +1712,9 @@ VarDecInt (MonoDecimal *pdecOprd, MonoDecimal *result)
        }
 }
 
-
-// VarDecNeg - Decimal Negate
-static void
-VarDecNeg (MonoDecimal *pdecOprd, MonoDecimal *result)
+// mono_decimal_negate - Decimal Negate
+static void G_GNUC_UNUSED
+mono_decimal_negate (MonoDecimal *pdecOprd, MonoDecimal *result)
 {
        COPYDEC(*result, *pdecOprd);
        // Microsoft does not set result->reserved to zero on this case.
@@ -1762,7 +1725,7 @@ VarDecNeg (MonoDecimal *pdecOprd, MonoDecimal *result)
 // Returns: MONO_DECIMAL_INVALID_ARGUMENT, MONO_DECIMAL_OK
 //
 static MonoDecimalStatus
-VarDecRound(MonoDecimal *input, int cDecimals, MonoDecimal *result)
+mono_decimal_round_result(MonoDecimal *input, int cDecimals, MonoDecimal *result)
 {
        uint32_t num[3];
        uint32_t rem;
@@ -1819,7 +1782,7 @@ VarDecRound(MonoDecimal *input, int cDecimals, MonoDecimal *result)
 //
 // Returns MONO_DECIMAL_OK or MONO_DECIMAL_OVERFLOW
 static MonoDecimalStatus
-VarDecFromR4 (float input, MonoDecimal* result)
+mono_decimal_from_float (float input_f, MonoDecimal* result)
 {
        int         exp;    // number of bits to left of binary point
        int         power;
@@ -1828,12 +1791,13 @@ VarDecFromR4 (float input, MonoDecimal* result)
        SPLIT64     sdlLo;
        SPLIT64     sdlHi;
        int         lmax, cur;  // temps used during scale reduction
-       
+       MonoSingle_float input = { .f = input_f };
+
        // The most we can scale by is 10^28, which is just slightly more
        // than 2^93.  So a float with an exponent of -94 could just
        // barely reach 0.5, but smaller exponents will always round to zero.
        //
-       if ((exp = ((SingleStructure *)&input)->exp - SNGBIAS) < -94 ) {
+       if ((exp = input.s.exp - MONO_SINGLE_BIAS) < -94 ) {
                DECIMAL_SETZERO(*result);
                return MONO_DECIMAL_OK;
        }
@@ -1849,7 +1813,7 @@ VarDecFromR4 (float input, MonoDecimal* result)
        // the exponent by log10(2).  Using scaled integer multiplcation, 
        // log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
        //
-       dbl = fabs(input);
+       dbl = fabs(input.f);
        power = 6 - ((exp * 19728) >> 16);
        
        if (power >= 0) {
@@ -1953,14 +1917,13 @@ VarDecFromR4 (float input, MonoDecimal* result)
                DECIMAL_SCALE(*result) = power;
        }
        
-       DECIMAL_SIGN(*result) = (char)((SingleStructure *)&input)->sign << 7;
+       DECIMAL_SIGN(*result) = (char)input.s.sign << 7;
        return MONO_DECIMAL_OK;
 }
 
-//
 // Returns MONO_DECIMAL_OK or MONO_DECIMAL_OVERFLOW
 static MonoDecimalStatus
-VarDecFromR8 (double input, MonoDecimal *result)
+mono_decimal_from_double (double input_d, MonoDecimal *result)
 {
        int         exp;    // number of bits to left of binary point
        int         power;  // power-of-10 scale factor
@@ -1970,13 +1933,13 @@ VarDecFromR8 (double input, MonoDecimal *result)
        int         lmax, cur;  // temps used during scale reduction
        uint32_t       pwr_cur;
        uint32_t       quo;
-       
+       MonoDouble_double input = { .d = input_d };
        
        // The most we can scale by is 10^28, which is just slightly more
        // than 2^93.  So a float with an exponent of -94 could just
        // barely reach 0.5, but smaller exponents will always round to zero.
        //
-       if ((exp = ((DoubleStructure *)&input)->u.exp - DBLBIAS) < -94) {
+       if ((exp = input.s.exp - MONO_DOUBLE_BIAS) < -94) {
                DECIMAL_SETZERO(*result);
                return MONO_DECIMAL_OK;
        }
@@ -1992,7 +1955,7 @@ VarDecFromR8 (double input, MonoDecimal *result)
        // the exponent by log10(2).  Using scaled integer multiplcation, 
        // log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
        //
-       dbl = fabs(input);
+       dbl = fabs(input.d);
        power = 14 - ((exp * 19728) >> 16);
        
        if (power >= 0) {
@@ -2103,13 +2066,13 @@ VarDecFromR8 (double input, MonoDecimal *result)
                DECIMAL_MID32(*result) = sdlMant.u.Hi;
        }
 
-       DECIMAL_SIGN(*result) = (char)((DoubleStructure *)&input)->u.sign << 7;
+       DECIMAL_SIGN(*result) = (char)input.s.sign << 7;
        return MONO_DECIMAL_OK;
 }
 
 // Returns: MONO_DECIMAL_OK, or MONO_DECIMAL_INVALID_ARGUMENT
 static MonoDecimalStatus
-VarR8FromDec(MonoDecimal *input, double *result)
+mono_decimal_to_double_result(MonoDecimal *input, double *result)
 {
        SPLIT64  tmp;
        double   dbl;
@@ -2121,11 +2084,11 @@ VarR8FromDec(MonoDecimal *input, double *result)
        tmp.u.Hi = DECIMAL_MID32(*input);
        
        if ((int32_t)DECIMAL_MID32(*input) < 0)
-               dbl = (ds2to64.dbl + (double)(int64_t)tmp.int64 +
-                      (double)DECIMAL_HI32(*input) * ds2to64.dbl) / fnDblPower10(DECIMAL_SCALE(*input)) ;
+               dbl = (ds2to64.d + (double)(int64_t)tmp.int64 +
+                      (double)DECIMAL_HI32(*input) * ds2to64.d) / fnDblPower10(DECIMAL_SCALE(*input)) ;
        else
                dbl = ((double)(int64_t)tmp.int64 +
-                      (double)DECIMAL_HI32(*input) * ds2to64.dbl) / fnDblPower10(DECIMAL_SCALE(*input));
+                      (double)DECIMAL_HI32(*input) * ds2to64.d) / fnDblPower10(DECIMAL_SCALE(*input));
        
        if (DECIMAL_SIGN(*input))
                dbl = -dbl;
@@ -2136,7 +2099,7 @@ VarR8FromDec(MonoDecimal *input, double *result)
 
 // Returns: MONO_DECIMAL_OK, or MONO_DECIMAL_INVALID_ARGUMENT
 static MonoDecimalStatus
-VarR4FromDec(MonoDecimal *input, float *result)
+mono_decimal_to_float_result(MonoDecimal *input, float *result)
 {
        double   dbl;
        
@@ -2145,7 +2108,7 @@ VarR4FromDec(MonoDecimal *input, float *result)
        
        // Can't overflow; no errors possible.
        //
-       VarR8FromDec(input, &dbl);
+       mono_decimal_to_double_result(input, &dbl);
        *result = (float)dbl;
        return MONO_DECIMAL_OK;
 }
@@ -2218,6 +2181,8 @@ mono_decimal_compare (MonoDecimal *left, MonoDecimal *right)
        uint32_t   right_sign;
        MonoDecimal result;
 
+       result.Hi32 = 0;        // Just to shut up the compiler
+
        // First check signs and whether either are zero.  If both are
        // non-zero and of the same sign, just use subtraction to compare.
        //
@@ -2245,9 +2210,9 @@ mono_decimal_compare (MonoDecimal *left, MonoDecimal *right)
        }
 
        //
-       // Signs are different.  Used signed byte compares
+       // Signs are different.  Use signed byte comparison
        //
-       if ((char)left_sign > (char)right_sign)
+       if ((signed char)left_sign > (signed char)right_sign)
                return MONO_DECIMAL_CMP_GT;
        return MONO_DECIMAL_CMP_LT;
 }
@@ -2255,7 +2220,7 @@ mono_decimal_compare (MonoDecimal *left, MonoDecimal *right)
 void
 mono_decimal_init_single (MonoDecimal *_this, float value)
 {
-       if (VarDecFromR4 (value, _this) == MONO_DECIMAL_OVERFLOW) {
+       if (mono_decimal_from_float (value, _this) == MONO_DECIMAL_OVERFLOW) {
                mono_set_pending_exception (mono_get_exception_overflow ());
                return;
        }
@@ -2265,7 +2230,7 @@ mono_decimal_init_single (MonoDecimal *_this, float value)
 void
 mono_decimal_init_double (MonoDecimal *_this, double value)
 {
-       if (VarDecFromR8 (value, _this) == MONO_DECIMAL_OVERFLOW) {
+       if (mono_decimal_from_double (value, _this) == MONO_DECIMAL_OVERFLOW) {
                mono_set_pending_exception (mono_get_exception_overflow ());
                return;
        }
@@ -2277,7 +2242,7 @@ mono_decimal_floor (MonoDecimal *d)
 {
        MonoDecimal decRes;
 
-       VarDecInt(d, &decRes);
+       mono_decimal_round_to_int(d, &decRes);
        
        // copy decRes into d
        COPYDEC(*d, decRes);
@@ -2290,7 +2255,7 @@ mono_decimal_get_hash_code (MonoDecimal *d)
 {
        double dbl;
 
-       if (VarR8FromDec(d, &dbl) != MONO_DECIMAL_OK)
+       if (mono_decimal_to_double_result(d, &dbl) != MONO_DECIMAL_OK)
                return 0;
        
        if (dbl == 0.0) {
@@ -2316,7 +2281,7 @@ mono_decimal_multiply (MonoDecimal *d1, MonoDecimal *d2)
 {
        MonoDecimal decRes;
 
-       MonoDecimalStatus status = VarDecMul(d1, d2, &decRes);
+       MonoDecimalStatus status = mono_decimal_multiply_result(d1, d2, &decRes);
        if (status != MONO_DECIMAL_OK) {
                mono_set_pending_exception (mono_get_exception_overflow ());
                return;
@@ -2339,7 +2304,7 @@ mono_decimal_round (MonoDecimal *d, int32_t decimals)
                return;
        }
 
-       VarDecRound(d, decimals, &decRes);
+       mono_decimal_round_result(d, decimals, &decRes);
 
        // copy decRes into d
        COPYDEC(*d, decRes);
@@ -2359,7 +2324,7 @@ mono_decimal_to_double (MonoDecimal d)
 {
        double result = 0.0;
        // Note: this can fail if the input is an invalid decimal, but for compatibility we should return 0
-       VarR8FromDec(&d, &result);
+       mono_decimal_to_double_result(&d, &result);
        return result;
 }
 
@@ -2369,11 +2334,11 @@ mono_decimal_to_int32 (MonoDecimal d)
        MonoDecimal result;
        
        // The following can not return an error, it only returns INVALID_ARG if the decimals is < 0
-       VarDecRound(&d, 0, &result);
+       mono_decimal_round_result(&d, 0, &result);
        
        if (DECIMAL_SCALE(result) != 0) {
                d = result;
-               VarDecFix (&d, &result);
+               mono_decimal_fix (&d, &result);
        }
        
        if (DECIMAL_HI32(result) == 0 && DECIMAL_MID32(result) == 0) {
@@ -2397,7 +2362,7 @@ mono_decimal_to_float (MonoDecimal d)
 {
        float result = 0.0f;
        // Note: this can fail if the input is an invalid decimal, but for compatibility we should return 0
-       VarR4FromDec(&d, &result);
+       mono_decimal_to_float_result(&d, &result);
        return result;
 }
 
@@ -2406,7 +2371,7 @@ mono_decimal_truncate (MonoDecimal *d)
 {
        MonoDecimal decRes;
 
-       VarDecFix(d, &decRes);
+       mono_decimal_fix(d, &decRes);
 
        // copy decRes into d
        COPYDEC(*d, decRes);
@@ -3062,19 +3027,11 @@ mono_decimal_divide (MonoDecimal *left, MonoDecimal *right)
 }
 
 #define DECIMAL_PRECISION 29
-#define NUMBER_MAXDIGITS 50
-typedef struct  {
-       int32_t precision;
-       int32_t scale;
-       int32_t sign;
-       uint16_t digits[NUMBER_MAXDIGITS + 1];
-       uint16_t* allDigits;
-} CLRNumber;
 
 int
 mono_decimal_from_number (void *from, MonoDecimal *target)
 {
-       CLRNumber *number = (CLRNumber *) from;
+       MonoNumber *number = (MonoNumber *) from;
        uint16_t* p = number->digits;
        MonoDecimal d;
        int e = number->scale;