Caffe2 - C++ API
A deep learning, cross platform ML framework
fixed_divisor.h
1 #ifndef CAFFE2_UTILS_FIXED_DIVISOR_H_
2 #define CAFFE2_UTILS_FIXED_DIVISOR_H_
3 
4 #include <cstdint>
5 #include <cstdio>
6 #include <cstdlib>
7 
8 // See Note [hip-clang differences to hcc]
9 
10 #if defined(__CUDA_ARCH__) || defined(__HIP_ARCH__) || defined(__HIP__)
11 #define FIXED_DIVISOR_DECL inline __host__ __device__
12 #else
13 #define FIXED_DIVISOR_DECL inline
14 #endif
15 
16 namespace caffe2 {
17 
18 // Utility class for quickly calculating quotients and remainders for
19 // a known integer divisor
20 template <typename T>
21 class FixedDivisor {};
22 
23 // Works for any positive divisor, 1 to INT_MAX. One 64-bit
24 // multiplication and one 64-bit shift is used to calculate the
25 // result.
26 template <>
27 class FixedDivisor<std::int32_t> {
28  public:
29  FixedDivisor() = default;
30 
31  explicit FixedDivisor(const std::int32_t d) : d_(d) {
32 #ifndef __HIP_PLATFORM_HCC__
33  CalcSignedMagic();
34 #endif // __HIP_PLATFORM_HCC__
35  }
36 
37  FIXED_DIVISOR_DECL std::int32_t d() const {
38  return d_;
39  }
40 
41 #ifndef __HIP_PLATFORM_HCC__
42  FIXED_DIVISOR_DECL std::uint64_t magic() const {
43  return magic_;
44  }
45 
46  FIXED_DIVISOR_DECL int shift() const {
47  return shift_;
48  }
49 #endif // __HIP_PLATFORM_HCC__
50 
52  FIXED_DIVISOR_DECL std::int32_t Div(const std::int32_t n) const {
53 #ifdef __HIP_PLATFORM_HCC__
54  return n / d_;
55 #else // __HIP_PLATFORM_HCC__
56  // In lieu of a mulhi instruction being available, perform the
57  // work in uint64
58  return (int32_t)((magic_ * (uint64_t)n) >> shift_);
59 #endif // __HIP_PLATFORM_HCC__
60  }
61 
63  FIXED_DIVISOR_DECL std::int32_t Mod(const std::int32_t n) const {
64  return n - d_ * Div(n);
65  }
66 
68  FIXED_DIVISOR_DECL void
69  DivMod(const std::int32_t n, std::int32_t* q, int32_t* r) const {
70  *q = Div(n);
71  *r = n - d_ * *q;
72  }
73 
74  private:
75 #ifndef __HIP_PLATFORM_HCC__
76  // Calculates magic multiplicative value and shift amount for calculating `q =
77  // n / d` for signed 32-bit integers.
78  // Implementation taken from Hacker's Delight section 10.
79  void CalcSignedMagic() {
80  if (d_ == 1) {
81  magic_ = UINT64_C(0x1) << 32;
82  shift_ = 32;
83  return;
84  }
85 
86  const std::uint32_t two31 = UINT32_C(0x80000000);
87  const std::uint32_t ad = std::abs(d_);
88  const std::uint32_t t = two31 + ((uint32_t)d_ >> 31);
89  const std::uint32_t anc = t - 1 - t % ad; // Absolute value of nc.
90  std::uint32_t p = 31; // Init. p.
91  std::uint32_t q1 = two31 / anc; // Init. q1 = 2**p/|nc|.
92  std::uint32_t r1 = two31 - q1 * anc; // Init. r1 = rem(2**p, |nc|).
93  std::uint32_t q2 = two31 / ad; // Init. q2 = 2**p/|d|.
94  std::uint32_t r2 = two31 - q2 * ad; // Init. r2 = rem(2**p, |d|).
95  std::uint32_t delta = 0;
96  do {
97  ++p;
98  q1 <<= 1; // Update q1 = 2**p/|nc|.
99  r1 <<= 1; // Update r1 = rem(2**p, |nc|).
100  if (r1 >= anc) { // (Must be an unsigned
101  ++q1; // comparison here).
102  r1 -= anc;
103  }
104  q2 <<= 1; // Update q2 = 2**p/|d|.
105  r2 <<= 1; // Update r2 = rem(2**p, |d|).
106  if (r2 >= ad) { // (Must be an unsigned
107  ++q2; // comparison here).
108  r2 -= ad;
109  }
110  delta = ad - r2;
111  } while (q1 < delta || (q1 == delta && r1 == 0));
112  std::int32_t magic = q2 + 1;
113  if (d_ < 0) {
114  magic = -magic;
115  }
116  shift_ = p;
117  magic_ = (std::uint64_t)(std::uint32_t)magic;
118  }
119 #endif // __HIP_PLATFORM_HCC__
120 
121  std::int32_t d_ = 1;
122 
123 #ifndef __HIP_PLATFORM_HCC__
124  std::uint64_t magic_;
125  int shift_;
126 #endif // __HIP_PLATFORM_HCC__
127 };
128 
129 } // namespace caffe2
130 
131 #endif // CAFFE2_UTILS_FIXED_DIVISOR_H_
FIXED_DIVISOR_DECL std::int32_t Mod(const std::int32_t n) const
Calculates r = n % d.
Definition: fixed_divisor.h:63
FIXED_DIVISOR_DECL std::int32_t Div(const std::int32_t n) const
Calculates q = n / d.
Definition: fixed_divisor.h:52
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13
FIXED_DIVISOR_DECL void DivMod(const std::int32_t n, std::int32_t *q, int32_t *r) const
Calculates q = n / d and r = n % d together.
Definition: fixed_divisor.h:69