ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / util / util_ssef.h
1 /*
2  * Copyright 2011-2013 Intel Corporation
3  * Modifications Copyright 2014, Blender Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0(the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #ifndef __UTIL_SSEF_H__
19 #define __UTIL_SSEF_H__
20
21 CCL_NAMESPACE_BEGIN
22
23 #ifdef __KERNEL_SSE2__
24
25 struct sseb;
26 struct ssef;
27
28 /*! 4-wide SSE float type. */
29 struct ssef {
30   typedef sseb Mask;   // mask type
31   typedef ssei Int;    // int type
32   typedef ssef Float;  // float type
33
34   enum { size = 4 };  // number of SIMD elements
35   union {
36     __m128 m128;
37     float f[4];
38     int i[4];
39   };  // data
40
41   ////////////////////////////////////////////////////////////////////////////////
42   /// Constructors, Assignment & Cast Operators
43   ////////////////////////////////////////////////////////////////////////////////
44
45   __forceinline ssef()
46   {
47   }
48   __forceinline ssef(const ssef &other)
49   {
50     m128 = other.m128;
51   }
52   __forceinline ssef &operator=(const ssef &other)
53   {
54     m128 = other.m128;
55     return *this;
56   }
57
58   __forceinline ssef(const __m128 a) : m128(a)
59   {
60   }
61   __forceinline operator const __m128 &() const
62   {
63     return m128;
64   }
65   __forceinline operator __m128 &()
66   {
67     return m128;
68   }
69
70   __forceinline ssef(float a) : m128(_mm_set1_ps(a))
71   {
72   }
73   __forceinline ssef(float a, float b, float c, float d) : m128(_mm_setr_ps(a, b, c, d))
74   {
75   }
76
77   __forceinline explicit ssef(const __m128i a) : m128(_mm_cvtepi32_ps(a))
78   {
79   }
80
81   ////////////////////////////////////////////////////////////////////////////////
82   /// Loads and Stores
83   ////////////////////////////////////////////////////////////////////////////////
84
85 #  if defined(__KERNEL_AVX__)
86   static __forceinline ssef broadcast(const void *const a)
87   {
88     return _mm_broadcast_ss((float *)a);
89   }
90 #  else
91   static __forceinline ssef broadcast(const void *const a)
92   {
93     return _mm_set1_ps(*(float *)a);
94   }
95 #  endif
96
97   ////////////////////////////////////////////////////////////////////////////////
98   /// Array Access
99   ////////////////////////////////////////////////////////////////////////////////
100
101   __forceinline const float &operator[](const size_t i) const
102   {
103     assert(i < 4);
104     return f[i];
105   }
106   __forceinline float &operator[](const size_t i)
107   {
108     assert(i < 4);
109     return f[i];
110   }
111 };
112
113 ////////////////////////////////////////////////////////////////////////////////
114 /// Unary Operators
115 ////////////////////////////////////////////////////////////////////////////////
116
117 __forceinline const ssef cast(const __m128i &a)
118 {
119   return _mm_castsi128_ps(a);
120 }
121 __forceinline const ssef operator+(const ssef &a)
122 {
123   return a;
124 }
125 __forceinline const ssef operator-(const ssef &a)
126 {
127   return _mm_xor_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000)));
128 }
129 __forceinline const ssef abs(const ssef &a)
130 {
131   return _mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)));
132 }
133 #  if defined(__KERNEL_SSE41__)
134 __forceinline const ssef sign(const ssef &a)
135 {
136   return _mm_blendv_ps(ssef(1.0f), -ssef(1.0f), _mm_cmplt_ps(a, ssef(0.0f)));
137 }
138 #  endif
139 __forceinline const ssef signmsk(const ssef &a)
140 {
141   return _mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000)));
142 }
143
144 __forceinline const ssef rcp(const ssef &a)
145 {
146   const ssef r = _mm_rcp_ps(a.m128);
147   return _mm_sub_ps(_mm_add_ps(r, r), _mm_mul_ps(_mm_mul_ps(r, r), a));
148 }
149 __forceinline const ssef sqr(const ssef &a)
150 {
151   return _mm_mul_ps(a, a);
152 }
153 __forceinline const ssef mm_sqrt(const ssef &a)
154 {
155   return _mm_sqrt_ps(a.m128);
156 }
157 __forceinline const ssef rsqrt(const ssef &a)
158 {
159   const ssef r = _mm_rsqrt_ps(a.m128);
160   return _mm_add_ps(
161       _mm_mul_ps(_mm_set_ps(1.5f, 1.5f, 1.5f, 1.5f), r),
162       _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(a, _mm_set_ps(-0.5f, -0.5f, -0.5f, -0.5f)), r),
163                  _mm_mul_ps(r, r)));
164 }
165
166 ////////////////////////////////////////////////////////////////////////////////
167 /// Binary Operators
168 ////////////////////////////////////////////////////////////////////////////////
169
170 __forceinline const ssef operator+(const ssef &a, const ssef &b)
171 {
172   return _mm_add_ps(a.m128, b.m128);
173 }
174 __forceinline const ssef operator+(const ssef &a, const float &b)
175 {
176   return a + ssef(b);
177 }
178 __forceinline const ssef operator+(const float &a, const ssef &b)
179 {
180   return ssef(a) + b;
181 }
182
183 __forceinline const ssef operator-(const ssef &a, const ssef &b)
184 {
185   return _mm_sub_ps(a.m128, b.m128);
186 }
187 __forceinline const ssef operator-(const ssef &a, const float &b)
188 {
189   return a - ssef(b);
190 }
191 __forceinline const ssef operator-(const float &a, const ssef &b)
192 {
193   return ssef(a) - b;
194 }
195
196 __forceinline const ssef operator*(const ssef &a, const ssef &b)
197 {
198   return _mm_mul_ps(a.m128, b.m128);
199 }
200 __forceinline const ssef operator*(const ssef &a, const float &b)
201 {
202   return a * ssef(b);
203 }
204 __forceinline const ssef operator*(const float &a, const ssef &b)
205 {
206   return ssef(a) * b;
207 }
208
209 __forceinline const ssef operator/(const ssef &a, const ssef &b)
210 {
211   return _mm_div_ps(a.m128, b.m128);
212 }
213 __forceinline const ssef operator/(const ssef &a, const float &b)
214 {
215   return a / ssef(b);
216 }
217 __forceinline const ssef operator/(const float &a, const ssef &b)
218 {
219   return ssef(a) / b;
220 }
221
222 __forceinline const ssef operator^(const ssef &a, const ssef &b)
223 {
224   return _mm_xor_ps(a.m128, b.m128);
225 }
226 __forceinline const ssef operator^(const ssef &a, const ssei &b)
227 {
228   return _mm_xor_ps(a.m128, _mm_castsi128_ps(b.m128));
229 }
230
231 __forceinline const ssef operator&(const ssef &a, const ssef &b)
232 {
233   return _mm_and_ps(a.m128, b.m128);
234 }
235 __forceinline const ssef operator&(const ssef &a, const ssei &b)
236 {
237   return _mm_and_ps(a.m128, _mm_castsi128_ps(b.m128));
238 }
239
240 __forceinline const ssef operator|(const ssef &a, const ssef &b)
241 {
242   return _mm_or_ps(a.m128, b.m128);
243 }
244 __forceinline const ssef operator|(const ssef &a, const ssei &b)
245 {
246   return _mm_or_ps(a.m128, _mm_castsi128_ps(b.m128));
247 }
248
249 __forceinline const ssef andnot(const ssef &a, const ssef &b)
250 {
251   return _mm_andnot_ps(a.m128, b.m128);
252 }
253
254 __forceinline const ssef min(const ssef &a, const ssef &b)
255 {
256   return _mm_min_ps(a.m128, b.m128);
257 }
258 __forceinline const ssef min(const ssef &a, const float &b)
259 {
260   return _mm_min_ps(a.m128, ssef(b));
261 }
262 __forceinline const ssef min(const float &a, const ssef &b)
263 {
264   return _mm_min_ps(ssef(a), b.m128);
265 }
266
267 __forceinline const ssef max(const ssef &a, const ssef &b)
268 {
269   return _mm_max_ps(a.m128, b.m128);
270 }
271 __forceinline const ssef max(const ssef &a, const float &b)
272 {
273   return _mm_max_ps(a.m128, ssef(b));
274 }
275 __forceinline const ssef max(const float &a, const ssef &b)
276 {
277   return _mm_max_ps(ssef(a), b.m128);
278 }
279
280 #  if defined(__KERNEL_SSE41__)
281 __forceinline ssef mini(const ssef &a, const ssef &b)
282 {
283   const ssei ai = _mm_castps_si128(a);
284   const ssei bi = _mm_castps_si128(b);
285   const ssei ci = _mm_min_epi32(ai, bi);
286   return _mm_castsi128_ps(ci);
287 }
288 #  endif
289
290 #  if defined(__KERNEL_SSE41__)
291 __forceinline ssef maxi(const ssef &a, const ssef &b)
292 {
293   const ssei ai = _mm_castps_si128(a);
294   const ssei bi = _mm_castps_si128(b);
295   const ssei ci = _mm_max_epi32(ai, bi);
296   return _mm_castsi128_ps(ci);
297 }
298 #  endif
299
300 ////////////////////////////////////////////////////////////////////////////////
301 /// Ternary Operators
302 ////////////////////////////////////////////////////////////////////////////////
303
304 #  if defined(__KERNEL_AVX2__)
305 __forceinline const ssef madd(const ssef &a, const ssef &b, const ssef &c)
306 {
307   return _mm_fmadd_ps(a, b, c);
308 }
309 __forceinline const ssef msub(const ssef &a, const ssef &b, const ssef &c)
310 {
311   return _mm_fmsub_ps(a, b, c);
312 }
313 __forceinline const ssef nmadd(const ssef &a, const ssef &b, const ssef &c)
314 {
315   return _mm_fnmadd_ps(a, b, c);
316 }
317 __forceinline const ssef nmsub(const ssef &a, const ssef &b, const ssef &c)
318 {
319   return _mm_fnmsub_ps(a, b, c);
320 }
321 #  else
322 __forceinline const ssef madd(const ssef &a, const ssef &b, const ssef &c)
323 {
324   return a * b + c;
325 }
326 __forceinline const ssef msub(const ssef &a, const ssef &b, const ssef &c)
327 {
328   return a * b - c;
329 }
330 __forceinline const ssef nmadd(const ssef &a, const ssef &b, const ssef &c)
331 {
332   return c - a * b;
333 }
334 __forceinline const ssef nmsub(const ssef &a, const ssef &b, const ssef &c)
335 {
336   return -a * b - c;
337 }
338 #  endif
339
340 ////////////////////////////////////////////////////////////////////////////////
341 /// Assignment Operators
342 ////////////////////////////////////////////////////////////////////////////////
343
344 __forceinline ssef &operator+=(ssef &a, const ssef &b)
345 {
346   return a = a + b;
347 }
348 __forceinline ssef &operator+=(ssef &a, const float &b)
349 {
350   return a = a + b;
351 }
352
353 __forceinline ssef &operator-=(ssef &a, const ssef &b)
354 {
355   return a = a - b;
356 }
357 __forceinline ssef &operator-=(ssef &a, const float &b)
358 {
359   return a = a - b;
360 }
361
362 __forceinline ssef &operator*=(ssef &a, const ssef &b)
363 {
364   return a = a * b;
365 }
366 __forceinline ssef &operator*=(ssef &a, const float &b)
367 {
368   return a = a * b;
369 }
370
371 __forceinline ssef &operator/=(ssef &a, const ssef &b)
372 {
373   return a = a / b;
374 }
375 __forceinline ssef &operator/=(ssef &a, const float &b)
376 {
377   return a = a / b;
378 }
379
380 ////////////////////////////////////////////////////////////////////////////////
381 /// Comparison Operators + Select
382 ////////////////////////////////////////////////////////////////////////////////
383
384 __forceinline const sseb operator==(const ssef &a, const ssef &b)
385 {
386   return _mm_cmpeq_ps(a.m128, b.m128);
387 }
388 __forceinline const sseb operator==(const ssef &a, const float &b)
389 {
390   return a == ssef(b);
391 }
392 __forceinline const sseb operator==(const float &a, const ssef &b)
393 {
394   return ssef(a) == b;
395 }
396
397 __forceinline const sseb operator!=(const ssef &a, const ssef &b)
398 {
399   return _mm_cmpneq_ps(a.m128, b.m128);
400 }
401 __forceinline const sseb operator!=(const ssef &a, const float &b)
402 {
403   return a != ssef(b);
404 }
405 __forceinline const sseb operator!=(const float &a, const ssef &b)
406 {
407   return ssef(a) != b;
408 }
409
410 __forceinline const sseb operator<(const ssef &a, const ssef &b)
411 {
412   return _mm_cmplt_ps(a.m128, b.m128);
413 }
414 __forceinline const sseb operator<(const ssef &a, const float &b)
415 {
416   return a < ssef(b);
417 }
418 __forceinline const sseb operator<(const float &a, const ssef &b)
419 {
420   return ssef(a) < b;
421 }
422
423 __forceinline const sseb operator>=(const ssef &a, const ssef &b)
424 {
425   return _mm_cmpnlt_ps(a.m128, b.m128);
426 }
427 __forceinline const sseb operator>=(const ssef &a, const float &b)
428 {
429   return a >= ssef(b);
430 }
431 __forceinline const sseb operator>=(const float &a, const ssef &b)
432 {
433   return ssef(a) >= b;
434 }
435
436 __forceinline const sseb operator>(const ssef &a, const ssef &b)
437 {
438   return _mm_cmpnle_ps(a.m128, b.m128);
439 }
440 __forceinline const sseb operator>(const ssef &a, const float &b)
441 {
442   return a > ssef(b);
443 }
444 __forceinline const sseb operator>(const float &a, const ssef &b)
445 {
446   return ssef(a) > b;
447 }
448
449 __forceinline const sseb operator<=(const ssef &a, const ssef &b)
450 {
451   return _mm_cmple_ps(a.m128, b.m128);
452 }
453 __forceinline const sseb operator<=(const ssef &a, const float &b)
454 {
455   return a <= ssef(b);
456 }
457 __forceinline const sseb operator<=(const float &a, const ssef &b)
458 {
459   return ssef(a) <= b;
460 }
461
462 __forceinline const ssef select(const sseb &m, const ssef &t, const ssef &f)
463 {
464 #  ifdef __KERNEL_SSE41__
465   return _mm_blendv_ps(f, t, m);
466 #  else
467   return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
468 #  endif
469 }
470
471 __forceinline const ssef select(const ssef &m, const ssef &t, const ssef &f)
472 {
473 #  ifdef __KERNEL_SSE41__
474   return _mm_blendv_ps(f, t, m);
475 #  else
476   return _mm_or_ps(_mm_and_ps(m, t), _mm_andnot_ps(m, f));
477 #  endif
478 }
479
480 __forceinline const ssef select(const int mask, const ssef &t, const ssef &f)
481 {
482 #  if defined(__KERNEL_SSE41__) && \
483       ((!defined(__clang__) && !defined(_MSC_VER)) || defined(__INTEL_COMPILER))
484   return _mm_blend_ps(f, t, mask);
485 #  else
486   return select(sseb(mask), t, f);
487 #  endif
488 }
489
490 ////////////////////////////////////////////////////////////////////////////////
491 /// Rounding Functions
492 ////////////////////////////////////////////////////////////////////////////////
493
494 #  if defined(__KERNEL_SSE41__)
495 __forceinline const ssef round_even(const ssef &a)
496 {
497   return _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT);
498 }
499 __forceinline const ssef round_down(const ssef &a)
500 {
501   return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF);
502 }
503 __forceinline const ssef round_up(const ssef &a)
504 {
505   return _mm_round_ps(a, _MM_FROUND_TO_POS_INF);
506 }
507 __forceinline const ssef round_zero(const ssef &a)
508 {
509   return _mm_round_ps(a, _MM_FROUND_TO_ZERO);
510 }
511 __forceinline const ssef floor(const ssef &a)
512 {
513   return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF);
514 }
515 __forceinline const ssef ceil(const ssef &a)
516 {
517   return _mm_round_ps(a, _MM_FROUND_TO_POS_INF);
518 }
519 #  endif
520
521 __forceinline ssei truncatei(const ssef &a)
522 {
523   return _mm_cvttps_epi32(a.m128);
524 }
525
526 __forceinline ssei floori(const ssef &a)
527 {
528 #  if defined(__KERNEL_SSE41__)
529   return ssei(floor(a));
530 #  else
531   return ssei(a - ssef(0.5f));
532 #  endif
533 }
534
535 ////////////////////////////////////////////////////////////////////////////////
536 /// Movement/Shifting/Shuffling Functions
537 ////////////////////////////////////////////////////////////////////////////////
538
539 __forceinline ssef unpacklo(const ssef &a, const ssef &b)
540 {
541   return _mm_unpacklo_ps(a.m128, b.m128);
542 }
543 __forceinline ssef unpackhi(const ssef &a, const ssef &b)
544 {
545   return _mm_unpackhi_ps(a.m128, b.m128);
546 }
547
548 template<size_t i0, size_t i1, size_t i2, size_t i3>
549 __forceinline const ssef shuffle(const ssef &b)
550 {
551   return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(i3, i2, i1, i0)));
552 }
553
554 template<> __forceinline const ssef shuffle<0, 1, 0, 1>(const ssef &a)
555 {
556   return _mm_movelh_ps(a, a);
557 }
558
559 template<> __forceinline const ssef shuffle<2, 3, 2, 3>(const ssef &a)
560 {
561   return _mm_movehl_ps(a, a);
562 }
563
564 template<size_t i0, size_t i1, size_t i2, size_t i3>
565 __forceinline const ssef shuffle(const ssef &a, const ssef &b)
566 {
567   return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i3, i2, i1, i0));
568 }
569
570 template<size_t i0> __forceinline const ssef shuffle(const ssef &a, const ssef &b)
571 {
572   return _mm_shuffle_ps(a, b, _MM_SHUFFLE(i0, i0, i0, i0));
573 }
574
575 template<> __forceinline const ssef shuffle<0, 1, 0, 1>(const ssef &a, const ssef &b)
576 {
577   return _mm_movelh_ps(a, b);
578 }
579
580 template<> __forceinline const ssef shuffle<2, 3, 2, 3>(const ssef &a, const ssef &b)
581 {
582   return _mm_movehl_ps(b, a);
583 }
584
585 #  if defined(__KERNEL_SSSE3__)
586 __forceinline const ssef shuffle8(const ssef &a, const ssei &shuf)
587 {
588   return _mm_castsi128_ps(_mm_shuffle_epi8(_mm_castps_si128(a), shuf));
589 }
590 #  endif
591
592 #  if defined(__KERNEL_SSE3__)
593 template<> __forceinline const ssef shuffle<0, 0, 2, 2>(const ssef &b)
594 {
595   return _mm_moveldup_ps(b);
596 }
597 template<> __forceinline const ssef shuffle<1, 1, 3, 3>(const ssef &b)
598 {
599   return _mm_movehdup_ps(b);
600 }
601 #  endif
602
603 template<size_t i0> __forceinline const ssef shuffle(const ssef &b)
604 {
605   return shuffle<i0, i0, i0, i0>(b);
606 }
607
608 #  if defined(__KERNEL_AVX__)
609 __forceinline const ssef shuffle(const ssef &a, const ssei &shuf)
610 {
611   return _mm_permutevar_ps(a, shuf);
612 }
613 #  endif
614
615 template<size_t i> __forceinline float extract(const ssef &a)
616 {
617   return _mm_cvtss_f32(shuffle<i, i, i, i>(a));
618 }
619 template<> __forceinline float extract<0>(const ssef &a)
620 {
621   return _mm_cvtss_f32(a);
622 }
623
624 #  if defined(__KERNEL_SSE41__)
625 template<size_t dst, size_t src, size_t clr>
626 __forceinline const ssef insert(const ssef &a, const ssef &b)
627 {
628   return _mm_insert_ps(a, b, (dst << 4) | (src << 6) | clr);
629 }
630 template<size_t dst, size_t src> __forceinline const ssef insert(const ssef &a, const ssef &b)
631 {
632   return insert<dst, src, 0>(a, b);
633 }
634 template<size_t dst> __forceinline const ssef insert(const ssef &a, const float b)
635 {
636   return insert<dst, 0>(a, _mm_set_ss(b));
637 }
638 #  else
639 template<size_t dst> __forceinline const ssef insert(const ssef &a, const float b)
640 {
641   ssef c = a;
642   c[dst] = b;
643   return c;
644 }
645 #  endif
646
647 ////////////////////////////////////////////////////////////////////////////////
648 /// Transpose
649 ////////////////////////////////////////////////////////////////////////////////
650
651 __forceinline void transpose(const ssef &r0,
652                              const ssef &r1,
653                              const ssef &r2,
654                              const ssef &r3,
655                              ssef &c0,
656                              ssef &c1,
657                              ssef &c2,
658                              ssef &c3)
659 {
660   ssef l02 = unpacklo(r0, r2);
661   ssef h02 = unpackhi(r0, r2);
662   ssef l13 = unpacklo(r1, r3);
663   ssef h13 = unpackhi(r1, r3);
664   c0 = unpacklo(l02, l13);
665   c1 = unpackhi(l02, l13);
666   c2 = unpacklo(h02, h13);
667   c3 = unpackhi(h02, h13);
668 }
669
670 __forceinline void transpose(
671     const ssef &r0, const ssef &r1, const ssef &r2, const ssef &r3, ssef &c0, ssef &c1, ssef &c2)
672 {
673   ssef l02 = unpacklo(r0, r2);
674   ssef h02 = unpackhi(r0, r2);
675   ssef l13 = unpacklo(r1, r3);
676   ssef h13 = unpackhi(r1, r3);
677   c0 = unpacklo(l02, l13);
678   c1 = unpackhi(l02, l13);
679   c2 = unpacklo(h02, h13);
680 }
681
682 ////////////////////////////////////////////////////////////////////////////////
683 /// Reductions
684 ////////////////////////////////////////////////////////////////////////////////
685
686 __forceinline const ssef vreduce_min(const ssef &v)
687 {
688   ssef h = min(shuffle<1, 0, 3, 2>(v), v);
689   return min(shuffle<2, 3, 0, 1>(h), h);
690 }
691 __forceinline const ssef vreduce_max(const ssef &v)
692 {
693   ssef h = max(shuffle<1, 0, 3, 2>(v), v);
694   return max(shuffle<2, 3, 0, 1>(h), h);
695 }
696 __forceinline const ssef vreduce_add(const ssef &v)
697 {
698   ssef h = shuffle<1, 0, 3, 2>(v) + v;
699   return shuffle<2, 3, 0, 1>(h) + h;
700 }
701
702 __forceinline float reduce_min(const ssef &v)
703 {
704   return _mm_cvtss_f32(vreduce_min(v));
705 }
706 __forceinline float reduce_max(const ssef &v)
707 {
708   return _mm_cvtss_f32(vreduce_max(v));
709 }
710 __forceinline float reduce_add(const ssef &v)
711 {
712   return _mm_cvtss_f32(vreduce_add(v));
713 }
714
715 __forceinline size_t select_min(const ssef &v)
716 {
717   return __bsf(movemask(v == vreduce_min(v)));
718 }
719 __forceinline size_t select_max(const ssef &v)
720 {
721   return __bsf(movemask(v == vreduce_max(v)));
722 }
723
724 __forceinline size_t select_min(const sseb &valid, const ssef &v)
725 {
726   const ssef a = select(valid, v, ssef(pos_inf));
727   return __bsf(movemask(valid & (a == vreduce_min(a))));
728 }
729 __forceinline size_t select_max(const sseb &valid, const ssef &v)
730 {
731   const ssef a = select(valid, v, ssef(neg_inf));
732   return __bsf(movemask(valid & (a == vreduce_max(a))));
733 }
734
735 __forceinline size_t movemask(const ssef &a)
736 {
737   return _mm_movemask_ps(a);
738 }
739
740 ////////////////////////////////////////////////////////////////////////////////
741 /// Memory load and store operations
742 ////////////////////////////////////////////////////////////////////////////////
743
744 __forceinline ssef load4f(const float4 &a)
745 {
746 #  ifdef __KERNEL_WITH_SSE_ALIGN__
747   return _mm_load_ps(&a.x);
748 #  else
749   return _mm_loadu_ps(&a.x);
750 #  endif
751 }
752
753 __forceinline ssef load4f(const float3 &a)
754 {
755 #  ifdef __KERNEL_WITH_SSE_ALIGN__
756   return _mm_load_ps(&a.x);
757 #  else
758   return _mm_loadu_ps(&a.x);
759 #  endif
760 }
761
762 __forceinline ssef load4f(const void *const a)
763 {
764   return _mm_load_ps((float *)a);
765 }
766
767 __forceinline ssef load1f_first(const float a)
768 {
769   return _mm_set_ss(a);
770 }
771
772 __forceinline void store4f(void *ptr, const ssef &v)
773 {
774   _mm_store_ps((float *)ptr, v);
775 }
776
777 __forceinline ssef loadu4f(const void *const a)
778 {
779   return _mm_loadu_ps((float *)a);
780 }
781
782 __forceinline void storeu4f(void *ptr, const ssef &v)
783 {
784   _mm_storeu_ps((float *)ptr, v);
785 }
786
787 __forceinline void store4f(const sseb &mask, void *ptr, const ssef &f)
788 {
789 #  if defined(__KERNEL_AVX__)
790   _mm_maskstore_ps((float *)ptr, (__m128i)mask, f);
791 #  else
792   *(ssef *)ptr = select(mask, f, *(ssef *)ptr);
793 #  endif
794 }
795
796 __forceinline ssef load4f_nt(void *ptr)
797 {
798 #  if defined(__KERNEL_SSE41__)
799   return _mm_castsi128_ps(_mm_stream_load_si128((__m128i *)ptr));
800 #  else
801   return _mm_load_ps((float *)ptr);
802 #  endif
803 }
804
805 __forceinline void store4f_nt(void *ptr, const ssef &v)
806 {
807 #  if defined(__KERNEL_SSE41__)
808   _mm_stream_ps((float *)ptr, v);
809 #  else
810   _mm_store_ps((float *)ptr, v);
811 #  endif
812 }
813
814 ////////////////////////////////////////////////////////////////////////////////
815 /// Euclidian Space Operators
816 ////////////////////////////////////////////////////////////////////////////////
817
818 __forceinline float dot(const ssef &a, const ssef &b)
819 {
820   return reduce_add(a * b);
821 }
822
823 /* calculate shuffled cross product, useful when order of components does not matter */
824 __forceinline ssef cross_zxy(const ssef &a, const ssef &b)
825 {
826   const ssef a0 = a;
827   const ssef b0 = shuffle<1, 2, 0, 3>(b);
828   const ssef a1 = shuffle<1, 2, 0, 3>(a);
829   const ssef b1 = b;
830   return msub(a0, b0, a1 * b1);
831 }
832
833 __forceinline ssef cross(const ssef &a, const ssef &b)
834 {
835   return shuffle<1, 2, 0, 3>(cross_zxy(a, b));
836 }
837
838 ccl_device_inline const ssef dot3_splat(const ssef &a, const ssef &b)
839 {
840 #  ifdef __KERNEL_SSE41__
841   return _mm_dp_ps(a.m128, b.m128, 0x7f);
842 #  else
843   ssef t = a * b;
844   return ssef(((float *)&t)[0] + ((float *)&t)[1] + ((float *)&t)[2]);
845 #  endif
846 }
847
848 /* squared length taking only specified axes into account */
849 template<size_t X, size_t Y, size_t Z, size_t W> ccl_device_inline float len_squared(const ssef &a)
850 {
851 #  ifndef __KERNEL_SSE41__
852   float4 &t = (float4 &)a;
853   return (X ? t.x * t.x : 0.0f) + (Y ? t.y * t.y : 0.0f) + (Z ? t.z * t.z : 0.0f) +
854          (W ? t.w * t.w : 0.0f);
855 #  else
856   return extract<0>(
857       ssef(_mm_dp_ps(a.m128, a.m128, (X << 4) | (Y << 5) | (Z << 6) | (W << 7) | 0xf)));
858 #  endif
859 }
860
861 ccl_device_inline float dot3(const ssef &a, const ssef &b)
862 {
863 #  ifdef __KERNEL_SSE41__
864   return extract<0>(ssef(_mm_dp_ps(a.m128, b.m128, 0x7f)));
865 #  else
866   ssef t = a * b;
867   return ((float *)&t)[0] + ((float *)&t)[1] + ((float *)&t)[2];
868 #  endif
869 }
870
871 ccl_device_inline const ssef len3_squared_splat(const ssef &a)
872 {
873   return dot3_splat(a, a);
874 }
875
876 ccl_device_inline float len3_squared(const ssef &a)
877 {
878   return dot3(a, a);
879 }
880
881 ccl_device_inline float len3(const ssef &a)
882 {
883   return extract<0>(mm_sqrt(dot3_splat(a, a)));
884 }
885
886 /* SSE shuffle utility functions */
887
888 #  ifdef __KERNEL_SSSE3__
889
890 /* faster version for SSSE3 */
891 typedef ssei shuffle_swap_t;
892
893 ccl_device_inline shuffle_swap_t shuffle_swap_identity()
894 {
895   return _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
896 }
897
898 ccl_device_inline shuffle_swap_t shuffle_swap_swap()
899 {
900   return _mm_set_epi8(7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8);
901 }
902
903 ccl_device_inline const ssef shuffle_swap(const ssef &a, const shuffle_swap_t &shuf)
904 {
905   return cast(_mm_shuffle_epi8(cast(a), shuf));
906 }
907
908 #  else
909
910 /* somewhat slower version for SSE2 */
911 typedef int shuffle_swap_t;
912
913 ccl_device_inline shuffle_swap_t shuffle_swap_identity()
914 {
915   return 0;
916 }
917
918 ccl_device_inline shuffle_swap_t shuffle_swap_swap()
919 {
920   return 1;
921 }
922
923 ccl_device_inline const ssef shuffle_swap(const ssef &a, shuffle_swap_t shuf)
924 {
925   /* shuffle value must be a constant, so we need to branch */
926   if (shuf)
927     return ssef(_mm_shuffle_ps(a.m128, a.m128, _MM_SHUFFLE(1, 0, 3, 2)));
928   else
929     return ssef(_mm_shuffle_ps(a.m128, a.m128, _MM_SHUFFLE(3, 2, 1, 0)));
930 }
931
932 #  endif
933
934 #  ifdef __KERNEL_SSE41__
935
936 ccl_device_inline void gen_idirsplat_swap(const ssef &pn,
937                                           const shuffle_swap_t &shuf_identity,
938                                           const shuffle_swap_t &shuf_swap,
939                                           const float3 &idir,
940                                           ssef idirsplat[3],
941                                           shuffle_swap_t shufflexyz[3])
942 {
943   const __m128 idirsplat_raw[] = {_mm_set_ps1(idir.x), _mm_set_ps1(idir.y), _mm_set_ps1(idir.z)};
944   idirsplat[0] = _mm_xor_ps(idirsplat_raw[0], pn);
945   idirsplat[1] = _mm_xor_ps(idirsplat_raw[1], pn);
946   idirsplat[2] = _mm_xor_ps(idirsplat_raw[2], pn);
947
948   const ssef signmask = cast(ssei(0x80000000));
949   const ssef shuf_identity_f = cast(shuf_identity);
950   const ssef shuf_swap_f = cast(shuf_swap);
951
952   shufflexyz[0] = _mm_castps_si128(
953       _mm_blendv_ps(shuf_identity_f, shuf_swap_f, _mm_and_ps(idirsplat_raw[0], signmask)));
954   shufflexyz[1] = _mm_castps_si128(
955       _mm_blendv_ps(shuf_identity_f, shuf_swap_f, _mm_and_ps(idirsplat_raw[1], signmask)));
956   shufflexyz[2] = _mm_castps_si128(
957       _mm_blendv_ps(shuf_identity_f, shuf_swap_f, _mm_and_ps(idirsplat_raw[2], signmask)));
958 }
959
960 #  else
961
962 ccl_device_inline void gen_idirsplat_swap(const ssef &pn,
963                                           const shuffle_swap_t &shuf_identity,
964                                           const shuffle_swap_t &shuf_swap,
965                                           const float3 &idir,
966                                           ssef idirsplat[3],
967                                           shuffle_swap_t shufflexyz[3])
968 {
969   idirsplat[0] = ssef(idir.x) ^ pn;
970   idirsplat[1] = ssef(idir.y) ^ pn;
971   idirsplat[2] = ssef(idir.z) ^ pn;
972
973   shufflexyz[0] = (idir.x >= 0) ? shuf_identity : shuf_swap;
974   shufflexyz[1] = (idir.y >= 0) ? shuf_identity : shuf_swap;
975   shufflexyz[2] = (idir.z >= 0) ? shuf_identity : shuf_swap;
976 }
977
978 #  endif
979
980 ccl_device_inline const ssef uint32_to_float(const ssei &in)
981 {
982   ssei a = _mm_srli_epi32(in, 16);
983   ssei b = _mm_and_si128(in, _mm_set1_epi32(0x0000ffff));
984   ssei c = _mm_or_si128(a, _mm_set1_epi32(0x53000000));
985   ssef d = _mm_cvtepi32_ps(b);
986   ssef e = _mm_sub_ps(_mm_castsi128_ps(c), _mm_castsi128_ps(_mm_set1_epi32(0x53000000)));
987   return _mm_add_ps(e, d);
988 }
989
990 template<size_t S1, size_t S2, size_t S3, size_t S4>
991 ccl_device_inline const ssef set_sign_bit(const ssef &a)
992 {
993   return cast(cast(a) ^ ssei(S1 << 31, S2 << 31, S3 << 31, S4 << 31));
994 }
995
996 ////////////////////////////////////////////////////////////////////////////////
997 /// Debug Functions
998 ////////////////////////////////////////////////////////////////////////////////
999
1000 ccl_device_inline void print_ssef(const char *label, const ssef &a)
1001 {
1002   printf(
1003       "%s: %.8f %.8f %.8f %.8f\n", label, (double)a[0], (double)a[1], (double)a[2], (double)a[3]);
1004 }
1005
1006 #endif
1007
1008 CCL_NAMESPACE_END
1009
1010 #endif