summaryrefslogtreecommitdiff
path: root/src/jit/utils.cpp
diff options
context:
space:
mode:
authorMike Danes <onemihaid@hotmail.com>2017-05-31 20:30:18 +0300
committerMike Danes <onemihaid@hotmail.com>2017-06-07 19:29:43 +0300
commit0435fbb7f154193dc3df35918e11945d0cf9e2b2 (patch)
tree2547e34ebccb9ca86092e05bdbdfacbcf20f5c93 /src/jit/utils.cpp
parent64a4d4969363dd8a96afece3ff48e1b20cccba68 (diff)
downloadcoreclr-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.cpp97
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
}