EigenRand  0.3.0
PacketFilter.h
Go to the documentation of this file.
1 
12 #ifndef EIGENRAND_PACKET_FILTER_H
13 #define EIGENRAND_PACKET_FILTER_H
14 
15 #include <array>
17 
18 namespace Eigen
19 {
20  namespace Rand
21  {
22  namespace detail
23  {
24  template<size_t PacketSize>
25  class CompressMask;
26  }
27  }
28 }
29 #ifdef EIGEN_VECTORIZE_AVX
30 #include <immintrin.h>
31 namespace Eigen
32 {
33  namespace Rand
34  {
35  namespace detail
36  {
37  template<>
38  class CompressMask<32>
39  {
40  std::array<std::array<internal::Packet8i, 256>, 15> idx;
41  std::array<internal::Packet8f, 8> selector;
42  std::array<uint8_t, 256> cnt;
43 
44  static internal::Packet8i make_compress(int mask, int offset = 0)
45  {
46  int32_t ret[8] = { 0, };
47  int n = offset;
48  for (int i = 0; i < 8; ++i)
49  {
50  int l = mask & 1;
51  mask >>= 1;
52  if (l)
53  {
54  if (n >= 0) ret[n] = i;
55  if (++n >= 8) break;
56  }
57  }
58  return _mm256_loadu_si256((internal::Packet8i*)ret);
59  }
60 
61  static uint8_t count(int mask)
62  {
63  uint8_t ret = 0;
64  for (int i = 0; i < 8; ++i)
65  {
66  ret += mask & 1;
67  mask >>= 1;
68  }
69  return ret;
70  }
71 
72  CompressMask()
73  {
74  for (int i = 0; i < 256; ++i)
75  {
76  for (int o = 0; o < 15; ++o)
77  {
78  idx[o][i] = make_compress(i, o < 8 ? o : o - 15);
79  }
80 
81  cnt[i] = count(i);
82  }
83 
84  selector[0] = _mm256_castsi256_ps(_mm256_setr_epi32(0, 0, 0, 0, 0, 0, 0, 0));
85  selector[1] = _mm256_castsi256_ps(_mm256_setr_epi32(-1, 0, 0, 0, 0, 0, 0, 0));
86  selector[2] = _mm256_castsi256_ps(_mm256_setr_epi32(-1, -1, 0, 0, 0, 0, 0, 0));
87  selector[3] = _mm256_castsi256_ps(_mm256_setr_epi32(-1, -1, -1, 0, 0, 0, 0, 0));
88  selector[4] = _mm256_castsi256_ps(_mm256_setr_epi32(-1, -1, -1, -1, 0, 0, 0, 0));
89  selector[5] = _mm256_castsi256_ps(_mm256_setr_epi32(-1, -1, -1, -1, -1, 0, 0, 0));
90  selector[6] = _mm256_castsi256_ps(_mm256_setr_epi32(-1, -1, -1, -1, -1, -1, 0, 0));
91  selector[7] = _mm256_castsi256_ps(_mm256_setr_epi32(-1, -1, -1, -1, -1, -1, -1, 0));
92  }
93 
94  static EIGEN_STRONG_INLINE internal::Packet8f permute(const internal::Packet8f& p, const internal::Packet8i& i)
95  {
96 #ifdef EIGEN_VECTORIZE_AVX2
97  return _mm256_permutevar8x32_ps(p, i);
98 #else
99  auto l = _mm256_permutevar_ps(p, i);
100  auto h = _mm256_permutevar_ps(_mm256_permute2f128_ps(p, p, 0x01), i);
101  internal::Packet4i i1, i2;
102  internal::split_two(i, i1, i2);
103  i1 = _mm_slli_epi32(i1, 29);
104  i2 = _mm_slli_epi32(i2, 29);
105  auto c = _mm256_castsi256_ps(
106  internal::combine_two(
107  _mm_cmplt_epi32(i1, internal::pset1<internal::Packet4i>(0)),
108  _mm_cmplt_epi32(internal::pset1<internal::Packet4i>(-1), i2)
109  )
110  );
111  return internal::pblendv(c, h, l);
112 #endif
113  }
114 
115  public:
116  enum { full_size = 8 };
117  static const CompressMask& get_inst()
118  {
119  static CompressMask cm;
120  return cm;
121  }
122 
123  template<typename Packet>
124  EIGEN_STRONG_INLINE int compress_append(Packet& _value, const Packet& _mask,
125  Packet& _rest, int rest_cnt, bool& full) const
126  {
127  auto& value = reinterpret_cast<internal::Packet8f&>(_value);
128  auto& mask = reinterpret_cast<const internal::Packet8f&>(_mask);
129  auto& rest = reinterpret_cast<internal::Packet8f&>(_rest);
130 
131  int m = _mm256_movemask_ps(mask);
132  if (cnt[m] == full_size)
133  {
134  full = true;
135  return rest_cnt;
136  }
137 
138  auto p1 = permute(value, idx[rest_cnt][m]);
139  p1 = internal::pblendv(selector[rest_cnt], rest, p1);
140 
141  auto new_cnt = rest_cnt + cnt[m];
142  if (new_cnt >= full_size)
143  {
144  if (new_cnt > full_size)
145  {
146  rest = permute(value, idx[new_cnt - cnt[m] + full_size - 1][m]);
147  }
148  value = p1;
149  full = true;
150  return new_cnt - full_size;
151  }
152  else
153  {
154  rest = p1;
155  full = false;
156  return new_cnt;
157  }
158  }
159  };
160  }
161  }
162 }
163 #endif
164 
165 #ifdef EIGEN_VECTORIZE_SSE2
166 #include <xmmintrin.h>
167 
168 namespace Eigen
169 {
170  namespace Rand
171  {
172  namespace detail
173  {
174  template<>
175  class CompressMask<16>
176  {
177  std::array<std::array<uint8_t, 16>, 7> idx;
178  std::array<internal::Packet4f, 4> selector;
179  std::array<uint8_t, 64> cnt;
180 
181  static uint8_t make_compress(int mask, int offset = 0)
182  {
183  uint8_t ret = 0;
184  int n = offset;
185  for (int i = 0; i < 4; ++i)
186  {
187  int l = mask & 1;
188  mask >>= 1;
189  if (l)
190  {
191  if (n >= 0) ret |= (i & 3) << (2 * n);
192  if (++n >= 4) break;
193  }
194  }
195  return ret;
196  }
197 
198  static uint8_t count(int mask)
199  {
200  uint8_t ret = 0;
201  for (int i = 0; i < 4; ++i)
202  {
203  ret += mask & 1;
204  mask >>= 1;
205  }
206  return ret;
207  }
208 
209  CompressMask()
210  {
211  for (int i = 0; i < 16; ++i)
212  {
213  for (int o = 0; o < 7; ++o)
214  {
215  idx[o][i] = make_compress(i, o < 4 ? o : o - 7);
216  }
217 
218  cnt[i] = count(i);
219  }
220 
221  selector[0] = _mm_castsi128_ps(_mm_setr_epi32(0, 0, 0, 0));
222  selector[1] = _mm_castsi128_ps(_mm_setr_epi32(-1, 0, 0, 0));
223  selector[2] = _mm_castsi128_ps(_mm_setr_epi32(-1, -1, 0, 0));
224  selector[3] = _mm_castsi128_ps(_mm_setr_epi32(-1, -1, -1, 0));
225  }
226 
227  static EIGEN_STRONG_INLINE internal::Packet4f permute(const internal::Packet4f& p, uint8_t i)
228  {
229  float u[4];
230  _mm_storeu_ps(u, p);
231  return _mm_setr_ps(u[i & 3], u[(i >> 2) & 3], u[(i >> 4) & 3], u[(i >> 6) & 3]);
232  }
233 
234  public:
235 
236  enum { full_size = 4 };
237 
238  static const CompressMask& get_inst()
239  {
240  static CompressMask cm;
241  return cm;
242  }
243 
244  template<typename Packet>
245  EIGEN_STRONG_INLINE int compress_append(Packet& _value, const Packet& _mask,
246  Packet& _rest, int rest_cnt, bool& full) const
247  {
248  auto& value = reinterpret_cast<internal::Packet4f&>(_value);
249  auto& mask = reinterpret_cast<const internal::Packet4f&>(_mask);
250  auto& rest = reinterpret_cast<internal::Packet4f&>(_rest);
251 
252  int m = _mm_movemask_ps(mask);
253  if (cnt[m] == full_size)
254  {
255  full = true;
256  return rest_cnt;
257  }
258 
259  auto p1 = permute(value, idx[rest_cnt][m]);
260  p1 = internal::pblendv(selector[rest_cnt], rest, p1);
261 
262  auto new_cnt = rest_cnt + cnt[m];
263  if (new_cnt >= full_size)
264  {
265  if (new_cnt > full_size)
266  {
267  rest = permute(value, idx[new_cnt - cnt[m] + full_size - 1][m]);
268  }
269  value = p1;
270  full = true;
271  return new_cnt - full_size;
272  }
273  else
274  {
275  rest = p1;
276  full = false;
277  return new_cnt;
278  }
279  }
280  };
281  }
282  }
283 }
284 #endif
285 
286 #endif