| 463 | */ |
| 464 | template <int BBits, int MBase, int SShift = BBits> |
| 465 | struct Swizzle { |
| 466 | static constexpr int num_bits = BBits; |
| 467 | static constexpr int num_base = MBase; |
| 468 | static constexpr int num_shft = SShift; |
| 469 | |
| 470 | static_assert(num_base >= 0, "MBase must be positive."); |
| 471 | static_assert(num_bits >= 0, "BBits must be positive."); |
| 472 | static_assert(abs(num_shft) >= num_bits, |
| 473 | "abs(SShift) must be more than BBits."); |
| 474 | |
| 475 | // using 'int' type here to avoid unintentially casting to unsigned... unsure. |
| 476 | using bit_msk = constant<int, (1 << num_bits) - 1>; |
| 477 | using yyy_msk = constant<int, bit_msk{} << (num_base + _max(0, num_shft))>; |
| 478 | using zzz_msk = constant<int, bit_msk{} << (num_base - _min(0, num_shft))>; |
| 479 | using msk_sft = constant<int, num_shft>; |
| 480 | |
| 481 | static constexpr uint32_t swizzle_code = uint32_t(yyy_msk{} | zzz_msk{}); |
| 482 | |
| 483 | template <class Offset> |
| 484 | HOST_DEVICE constexpr static auto apply(Offset const& offset) { |
| 485 | return offset ^ shiftr(offset & yyy_msk{}, msk_sft{}); // ZZZ ^= YYY |
| 486 | } |
| 487 | |
| 488 | template <class Offset> |
| 489 | HOST_DEVICE constexpr auto operator()(Offset const& offset) const { |
| 490 | return apply(offset); |
| 491 | } |
| 492 | }; |
| 493 | |
| 494 | /// Returns a warp index in the CTA. The threads in warp may not be convergent |
| 495 | /// As it doesn't sync the warp, it faster and allows forward progress |