diff options
author | Mike Danes <onemihaid@hotmail.com> | 2017-05-31 20:30:18 +0300 |
---|---|---|
committer | Mike Danes <onemihaid@hotmail.com> | 2017-06-07 19:29:43 +0300 |
commit | 0435fbb7f154193dc3df35918e11945d0cf9e2b2 (patch) | |
tree | 2547e34ebccb9ca86092e05bdbdfacbcf20f5c93 /src/jit/utils.cpp | |
parent | 64a4d4969363dd8a96afece3ff48e1b20cccba68 (diff) | |
download | coreclr-0435fbb7f154193dc3df35918e11945d0cf9e2b2.tar.gz coreclr-0435fbb7f154193dc3df35918e11945d0cf9e2b2.tar.bz2 coreclr-0435fbb7f154193dc3df35918e11945d0cf9e2b2.zip |
Move GetSignedMagicNumberForDivide to utils.cpp
Diffstat (limited to 'src/jit/utils.cpp')
-rw-r--r-- | src/jit/utils.cpp | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/jit/utils.cpp b/src/jit/utils.cpp index c8f770f1a3..dda55fced3 100644 --- a/src/jit/utils.cpp +++ b/src/jit/utils.cpp @@ -1984,4 +1984,101 @@ uint64_t GetUnsigned64Magic(uint64_t d, bool* add /*out*/, int* shift /*out*/) return GetUnsignedMagic<uint64_t>(d, add, shift); } #endif + +//------------------------------------------------------------------------ +// GetSignedMagic: Generates a magic number and shift amount for +// the magic number division optimization. +// +// Arguments: +// denom - The denominator +// shift - Pointer to the shift value to be returned +// +// Returns: +// The magic number. +// +// Notes: +// This code is previously from UTC where it notes it was taken from +// _The_PowerPC_Compiler_Writer's_Guide_, pages 57-58. The paper is is based on +// is "Division by invariant integers using multiplication" by Torbjorn Granlund +// and Peter L. Montgomery in PLDI 94 + +template <typename T> +T GetSignedMagic(T denom, int* shift /*out*/) +{ + // static SMAG smag; + const int bits = sizeof(T) * 8; + const int bits_minus_1 = bits - 1; + + typedef typename jitstd::make_unsigned<T>::type UT; + + const UT two_nminus1 = UT(1) << bits_minus_1; + + int p; + UT absDenom; + UT absNc; + UT delta; + UT q1; + UT r1; + UT r2; + UT q2; + UT t; + T result_magic; + int result_shift; + int iters = 0; + + absDenom = abs(denom); + t = two_nminus1 + ((unsigned int)denom >> 31); + absNc = t - 1 - (t % absDenom); // absolute value of nc + p = bits_minus_1; // initialize p + q1 = two_nminus1 / absNc; // initialize q1 = 2^p / abs(nc) + r1 = two_nminus1 - (q1 * absNc); // initialize r1 = rem(2^p, abs(nc)) + q2 = two_nminus1 / absDenom; // initialize q1 = 2^p / abs(denom) + r2 = two_nminus1 - (q2 * absDenom); // initialize r1 = rem(2^p, abs(denom)) + + do + { + iters++; + p++; + q1 *= 2; // update q1 = 2^p / abs(nc) + r1 *= 2; // update r1 = rem(2^p / abs(nc)) + + if (r1 >= absNc) + { // must be unsigned comparison + q1++; + r1 -= absNc; + } + + q2 *= 2; // update q2 = 2^p / abs(denom) + r2 *= 2; // update r2 = rem(2^p / abs(denom)) + + if (r2 >= absDenom) + { // must be unsigned comparison + q2++; + r2 -= absDenom; + } + + delta = absDenom - r2; + } while (q1 < delta || (q1 == delta && r1 == 0)); + + result_magic = q2 + 1; // resulting magic number + if (denom < 0) + { + result_magic = -result_magic; + } + *shift = p - bits; // resulting shift + + return result_magic; +} + +int32_t GetSigned32Magic(int32_t d, int* shift /*out*/) +{ + return GetSignedMagic<int32_t>(d, shift); +} + +#ifdef _TARGET_64BIT_ +int64_t GetSigned64Magic(int64_t d, int* shift /*out*/) +{ + return GetSignedMagic<int64_t>(d, shift); +} +#endif } |