openMSX
DivModBySame.hh
Go to the documentation of this file.
1#ifndef DIVISIONBYCONST_HH
2#define DIVISIONBYCONST_HH
3
4#include "narrow.hh"
5#include <cassert>
6#include <cstdint>
7#include <utility>
8
9namespace openmsx {
10
26{
27public:
28 void setDivisor(uint32_t divisor);
29 [[nodiscard]] inline uint32_t getDivisor() const { return divisor; }
30
31 [[nodiscard]] uint32_t div(uint64_t dividend) const
32 {
33 #if defined __x86_64 && !defined _MSC_VER
34 auto t = narrow_cast<uint64_t>((__uint128_t(dividend) * m + a) >> 64);
35 return narrow_cast<uint32_t>(t >> s);
36 #else
37 return divInC(dividend);
38 #endif
39 }
40
41 [[nodiscard]] inline uint32_t divInC(uint64_t dividend) const
42 {
43 uint64_t t1 = uint64_t(uint32_t(dividend)) * uint32_t(m);
44 uint64_t t2 = (dividend >> 32) * uint32_t(m);
45 uint64_t t3 = uint32_t(dividend) * (m >> 32);
46 uint64_t t4 = (dividend >> 32) * (m >> 32);
47
48 uint64_t s1 = uint64_t(uint32_t(a)) + uint32_t(t1);
49 uint64_t s2 = (s1 >> 32) + (a >> 32) + (t1 >> 32) + t2;
50 uint64_t s3 = uint64_t(uint32_t(s2)) + uint32_t(t3);
51 uint64_t s4 = (s3 >> 32) + (s2 >> 32) + (t3 >> 32) + t4;
52
53 uint64_t result = s4 >> s;
54 #ifdef DEBUG
55 // we don't even want this overhead in devel builds
56 assert(result == uint32_t(result));
57 #endif
58 return uint32_t(result);
59 }
60
61 [[nodiscard]] std::pair<uint32_t, uint32_t> divMod(uint64_t dividend) const
62 {
63 assert(uint32_t(divisor) == divisor); // must fit in 32-bit
64 uint64_t q = div(dividend);
65 assert(uint32_t(q) == q); // must fit in 32 bit
66 // result fits in 32-bit, so no 64-bit calculations required
67 uint32_t r = uint32_t(dividend) - uint32_t(q) * uint32_t(divisor);
68 return {uint32_t(q), r};
69 }
70
71 [[nodiscard]] uint32_t mod(uint64_t dividend) const
72 {
73 auto [q, r] = divMod(dividend);
74 (void)q;
75 return r;
76 }
77
78private:
79 uint64_t m = 0;
80 uint64_t a = 0;
81 uint32_t s = 0;
82 uint32_t divisor= 0; // only used by mod() and getDivisor()
83};
84
85} // namespace openmsx
86
87#endif // DIVISIONBYCONST_HH
TclObject t
Helper class to divide multiple times by the same number.
uint32_t div(uint64_t dividend) const
uint32_t mod(uint64_t dividend) const
uint32_t divInC(uint64_t dividend) const
uint32_t getDivisor() const
std::pair< uint32_t, uint32_t > divMod(uint64_t dividend) const
void setDivisor(uint32_t divisor)
This file implemented 3 utility functions:
Definition Autofire.cc:11