3#include "native/config.h"
12namespace native::detail {
14 constexpr U bmi2_zero_high(U value,
unsigned index)
noexcept {
16 return index >=
sizeof(U) * 8 ? value : U(value & ((U{1} << index) - U{1}));
20 constexpr U bmi2_deposit(U value, U
mask)
noexcept {
23 if (value & bit) result |=
mask & (U{0} -
mask);
28 constexpr U bmi2_extract(U value, U
mask)
noexcept {
31 if (value & (
mask & (U{0} -
mask))) result |= bit;
35 constexpr std::uint32_t bmi2_multiply(std::uint32_t a, std::uint32_t b,
36 std::uint32_t* high)
noexcept {
37 auto product = std::uint64_t{a} * b;
38 *high =
static_cast<std::uint32_t
>(product >> 32);
39 return static_cast<std::uint32_t
>(product);
42 constexpr std::uint64_t bmi2_multiply(std::uint64_t a, std::uint64_t b,
43 std::uint64_t* high)
noexcept {
45 auto a_low = std::uint64_t{
static_cast<std::uint32_t
>(a)};
46 auto b_low = std::uint64_t{
static_cast<std::uint32_t
>(b)};
47 auto a_high = a >> 32;
48 auto b_high = b >> 32;
49 auto low_product = a_low * b_low;
50 auto middle = a_high * b_low + (low_product >> 32);
51 auto upper = middle >> 32;
52 middle = std::uint64_t{
static_cast<std::uint32_t
>(middle)} + a_low * b_high;
53 *high = a_high * b_high + upper + (middle >> 32);
54 return (middle << 32) |
static_cast<std::uint32_t
>(low_product);
66 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
68 constexpr
std::uint32_t
bzhi(
std::uint32_t value,
unsigned index) noexcept {
69 if (__builtin_is_constant_evaluated()) {
70 return detail::bmi2_zero_high(value, index);
72 return _bzhi_u32(value, index);
76 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
78 constexpr std::uint64_t
bzhi(std::uint64_t value,
unsigned index)
noexcept {
79 if (__builtin_is_constant_evaluated()) {
80 return detail::bmi2_zero_high(value, index);
82 return _bzhi_u64(value, index);
87 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
89 constexpr std::uint32_t
mulx(std::uint32_t a, std::uint32_t b, std::uint32_t* high)
noexcept {
90 if (__builtin_is_constant_evaluated()) {
91 return detail::bmi2_multiply(a, b, high);
94 auto lower = _mulx_u32(a, b, &upper);
100 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
102 constexpr std::uint64_t
mulx(std::uint64_t a, std::uint64_t b, std::uint64_t* high)
noexcept {
103 if (__builtin_is_constant_evaluated()) {
104 return detail::bmi2_multiply(a, b, high);
107 unsigned long long upper;
108 auto lower = _mulx_u64(a, b, &upper);
115 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
117 constexpr std::uint32_t
pdep(std::uint32_t value, std::uint32_t
mask)
noexcept {
118 if (__builtin_is_constant_evaluated()) {
119 return detail::bmi2_deposit(value,
mask);
121 return _pdep_u32(value,
mask);
125 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
127 constexpr std::uint64_t
pdep(std::uint64_t value, std::uint64_t
mask)
noexcept {
128 if (__builtin_is_constant_evaluated()) {
129 return detail::bmi2_deposit(value,
mask);
131 return _pdep_u64(value,
mask);
136 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
138 constexpr std::uint32_t
pext(std::uint32_t value, std::uint32_t
mask)
noexcept {
139 if (__builtin_is_constant_evaluated()) {
140 return detail::bmi2_extract(value,
mask);
142 return _pext_u32(value,
mask);
146 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
148 constexpr std::uint64_t
pext(std::uint64_t value, std::uint64_t
mask)
noexcept {
149 if (__builtin_is_constant_evaluated()) {
150 return detail::bmi2_extract(value,
mask);
152 return _pext_u64(value,
mask);
157 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
159 constexpr std::uint32_t
shlx(std::uint32_t value,
unsigned count)
noexcept {
160 return value << (count & 31u);
163 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
165 constexpr std::uint64_t
shlx(std::uint64_t value,
unsigned count)
noexcept {
166 return value << (count & 63u);
170 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
172 constexpr std::uint32_t
shrx(std::uint32_t value,
unsigned count)
noexcept {
173 return value >> (count & 31u);
176 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
178 constexpr std::uint64_t
shrx(std::uint64_t value,
unsigned count)
noexcept {
179 return value >> (count & 63u);
183 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
185 constexpr std::int32_t
sarx(std::int32_t value,
unsigned count)
noexcept {
186 return value >> (count & 31u);
189 template<isa<x86> Arch>
requires(Arch.has(x86_feature::bmi2))
191 constexpr std::int64_t
sarx(std::int64_t value,
unsigned count)
noexcept {
192 return value >> (count & 63u);
196 template<isa<x86> Arch,
unsigned Imm8>
requires(Arch.has(x86_feature::bmi2) && Imm8 <= 255)
198 constexpr std::uint32_t
rorx(std::uint32_t value)
noexcept {
199 return std::rotr(value,
int(Imm8));
202 template<isa<x86> Arch,
unsigned Imm8>
requires(Arch.has(x86_feature::bmi2) && Imm8 <= 255)
204 constexpr std::uint64_t
rorx(std::uint64_t value)
noexcept {
205 return std::rotr(value,
int(Imm8));
210 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
212 consteval std::uint32_t
bzhi(std::uint32_t value,
unsigned index)
noexcept {
217 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
219 consteval std::uint64_t
bzhi(std::uint64_t value,
unsigned index)
noexcept {
224 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
226 consteval std::uint32_t
mulx(std::uint32_t a, std::uint32_t b, std::uint32_t* high)
noexcept {
231 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
233 consteval std::uint64_t
mulx(std::uint64_t a, std::uint64_t b, std::uint64_t* high)
noexcept {
238 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
240 consteval std::uint32_t
pdep(std::uint32_t value, std::uint32_t
mask)
noexcept {
245 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
247 consteval std::uint64_t
pdep(std::uint64_t value, std::uint64_t
mask)
noexcept {
252 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
254 consteval std::uint32_t
pext(std::uint32_t value, std::uint32_t
mask)
noexcept {
259 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
261 consteval std::uint64_t
pext(std::uint64_t value, std::uint64_t
mask)
noexcept {
266 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
268 consteval std::uint32_t
shlx(std::uint32_t value,
unsigned count)
noexcept {
273 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
275 consteval std::uint64_t
shlx(std::uint64_t value,
unsigned count)
noexcept {
280 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
282 consteval std::uint32_t
shrx(std::uint32_t value,
unsigned count)
noexcept {
287 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
289 consteval std::uint64_t
shrx(std::uint64_t value,
unsigned count)
noexcept {
294 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
296 consteval std::int32_t
sarx(std::int32_t value,
unsigned count)
noexcept {
301 template<isa<x86> Arch>
requires(!Arch.has(x86_feature::bmi2))
303 consteval std::int64_t
sarx(std::int64_t value,
unsigned count)
noexcept {
308 template<isa<x86> Arch,
unsigned Imm8>
requires(!Arch.has(x86_feature::bmi2) && Imm8 <= 255)
310 consteval std::uint32_t
rorx(std::uint32_t value)
noexcept {
315 template<isa<x86> Arch,
unsigned Imm8>
requires(!Arch.has(x86_feature::bmi2) && Imm8 <= 255)
317 consteval std::uint64_t
rorx(std::uint64_t value)
noexcept {
Compiler attributes for host code, with shader-safe shared modifiers.
#define native_inline
inline [[always_inline]]
#define native_nodiscard
C++17 [[nodiscard]].
#define native_const
[[const]] is not const
typename mask_traits< std::remove_cvref_t< T > >::type mask
constexpr std::uint32_t pdep(std::uint32_t value, std::uint32_t mask) noexcept
Parallel bit deposit (PDEP): place the low popcount(mask) bits into mask's set positions,...
constexpr std::uint32_t bzhi(std::uint32_t value, unsigned index) noexcept
Zero bits at and above index's low eight bits; an index at least the width leaves value unchanged.
constexpr std::uint32_t mulx(std::uint32_t a, std::uint32_t b, std::uint32_t *high) noexcept
Return the low product and write the high product to a valid output pointer.
constexpr std::int32_t sarx(std::int32_t value, unsigned count) noexcept
Arithmetic right shift using the low five bits of count, propagating the sign bit.
constexpr std::uint32_t pext(std::uint32_t value, std::uint32_t mask) noexcept
Parallel bit extract (PEXT): gather mask's selected bits into the low bits, in order.
constexpr std::uint32_t shlx(std::uint32_t value, unsigned count) noexcept
Logical left shift using the low five bits of count.
constexpr std::uint32_t shrx(std::uint32_t value, unsigned count) noexcept
Logical right shift using the low five bits of count.
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
constexpr std::uint32_t rorx(std::uint32_t value) noexcept
constexpr int target
First matching requirement, with every later choice checked for shadowing.
Standard-library adaptations documented here for SIMD value types.