summaryrefslogtreecommitdiff
path: root/src/jit/utils.cpp
diff options
context:
space:
mode:
authorMike Danes <onemihaid@hotmail.com>2017-04-15 21:43:14 +0300
committerMike Danes <onemihaid@hotmail.com>2017-06-07 19:29:37 +0300
commit64a4d4969363dd8a96afece3ff48e1b20cccba68 (patch)
tree7c05f325dad5a1bc612dc85f27e8359bf7a6c491 /src/jit/utils.cpp
parent5b9680fcc9b6fe9429f4a649bf5215de273fcbec (diff)
downloadcoreclr-64a4d4969363dd8a96afece3ff48e1b20cccba68.tar.gz
coreclr-64a4d4969363dd8a96afece3ff48e1b20cccba68.tar.bz2
coreclr-64a4d4969363dd8a96afece3ff48e1b20cccba68.zip
Do unsigned magic division
Diffstat (limited to 'src/jit/utils.cpp')
-rw-r--r--src/jit/utils.cpp177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/jit/utils.cpp b/src/jit/utils.cpp
index 9fbe394a21..c8f770f1a3 100644
--- a/src/jit/utils.cpp
+++ b/src/jit/utils.cpp
@@ -1808,3 +1808,180 @@ float FloatingPointUtils::round(float x)
return _copysignf(flrTempVal, x);
}
+
+namespace MagicDivide
+{
+template <int TableBase = 0, int TableSize, typename Magic>
+static const Magic* TryGetMagic(const Magic (&table)[TableSize], typename Magic::DivisorType index)
+{
+ if ((index < TableBase) || (TableBase + TableSize <= index))
+ {
+ return nullptr;
+ }
+
+ const Magic* p = &table[index - TableBase];
+
+ if (p->magic == 0)
+ {
+ return nullptr;
+ }
+
+ return p;
+};
+
+template <typename T>
+struct UnsignedMagic
+{
+ typedef T DivisorType;
+
+ T magic;
+ bool add;
+ int shift;
+};
+
+template <typename T>
+const UnsignedMagic<T>* TryGetUnsignedMagic(T divisor)
+{
+ return nullptr;
+}
+
+template <>
+const UnsignedMagic<uint32_t>* TryGetUnsignedMagic(uint32_t divisor)
+{
+ static const UnsignedMagic<uint32_t> table[]{
+ {0xaaaaaaab, false, 1}, // 3
+ {},
+ {0xcccccccd, false, 2}, // 5
+ {0xaaaaaaab, false, 2}, // 6
+ {0x24924925, true, 3}, // 7
+ {},
+ {0x38e38e39, false, 1}, // 9
+ {0xcccccccd, false, 3}, // 10
+ {0xba2e8ba3, false, 3}, // 11
+ {0xaaaaaaab, false, 3}, // 12
+ };
+
+ return TryGetMagic<3>(table, divisor);
+}
+
+template <>
+const UnsignedMagic<uint64_t>* TryGetUnsignedMagic(uint64_t divisor)
+{
+ static const UnsignedMagic<uint64_t> table[]{
+ {0xaaaaaaaaaaaaaaab, false, 1}, // 3
+ {},
+ {0xcccccccccccccccd, false, 2}, // 5
+ {0xaaaaaaaaaaaaaaab, false, 2}, // 6
+ {0x2492492492492493, true, 3}, // 7
+ {},
+ {0xe38e38e38e38e38f, false, 3}, // 9
+ {0xcccccccccccccccd, false, 3}, // 10
+ {0x2e8ba2e8ba2e8ba3, false, 1}, // 11
+ {0xaaaaaaaaaaaaaaab, false, 3}, // 12
+ };
+
+ return TryGetMagic<3>(table, divisor);
+}
+
+//------------------------------------------------------------------------
+// GetUnsignedMagic: Generates a magic number and shift amount for the magic
+// number unsigned division optimization.
+//
+// Arguments:
+// d - The divisor
+// add - Pointer to a flag indicating the kind of code to generate
+// shift - Pointer to the shift value to be returned
+//
+// Returns:
+// The magic number.
+//
+// Notes:
+// This code is adapted from _The_PowerPC_Compiler_Writer's_Guide_, pages 57-58.
+// The paper is based on "Division by invariant integers using multiplication"
+// by Torbjorn Granlund and Peter L. Montgomery in PLDI 94
+
+template <typename T>
+T GetUnsignedMagic(T d, bool* add /*out*/, int* shift /*out*/)
+{
+ assert((d >= 3) && !isPow2(d));
+
+ const UnsignedMagic<T>* magic = TryGetUnsignedMagic(d);
+
+ if (magic != nullptr)
+ {
+ *shift = magic->shift;
+ *add = magic->add;
+ return magic->magic;
+ }
+
+ typedef typename jitstd::make_signed<T>::type ST;
+
+ const unsigned bits = sizeof(T) * 8;
+ const unsigned bitsMinus1 = bits - 1;
+ const T twoNMinus1 = T(1) << bitsMinus1;
+
+ *add = false;
+ const T nc = -ST(1) - -ST(d) % ST(d);
+ unsigned p = bitsMinus1;
+ T q1 = twoNMinus1 / nc;
+ T r1 = twoNMinus1 - (q1 * nc);
+ T q2 = (twoNMinus1 - 1) / d;
+ T r2 = (twoNMinus1 - 1) - (q2 * d);
+ T delta;
+
+ do
+ {
+ p++;
+
+ if (r1 >= (nc - r1))
+ {
+ q1 = 2 * q1 + 1;
+ r1 = 2 * r1 - nc;
+ }
+ else
+ {
+ q1 = 2 * q1;
+ r1 = 2 * r1;
+ }
+
+ if ((r2 + 1) >= (d - r2))
+ {
+ if (q2 >= (twoNMinus1 - 1))
+ {
+ *add = true;
+ }
+
+ q2 = 2 * q2 + 1;
+ r2 = 2 * r2 + 1 - d;
+ }
+ else
+ {
+ if (q2 >= twoNMinus1)
+ {
+ *add = true;
+ }
+
+ q2 = 2 * q2;
+ r2 = 2 * r2 + 1;
+ }
+
+ delta = d - 1 - r2;
+
+ } while ((p < (bits * 2)) && ((q1 < delta) || ((q1 == delta) && (r1 == 0))));
+
+ *shift = p - bits; // resulting shift
+ return q2 + 1; // resulting magic number
+}
+
+uint32_t GetUnsigned32Magic(uint32_t d, bool* add /*out*/, int* shift /*out*/)
+{
+ return GetUnsignedMagic<uint32_t>(d, add, shift);
+}
+
+#ifdef _TARGET_64BIT_
+uint64_t GetUnsigned64Magic(uint64_t d, bool* add /*out*/, int* shift /*out*/)
+{
+ return GetUnsignedMagic<uint64_t>(d, add, shift);
+}
+#endif
+}