native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
bmi1.h
1// SPDX-FileCopyrightText: 2026 Edward Kmett <ekmett@gmail.com>
2// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0
3#pragma once
4#include "native/config.h"
5#include "native/attributes.h"
6#include "native/isa.h"
7#include <bit>
8#include <cstdint>
9#if NATIVE_HOST_X86
10#include <immintrin.h>
11
12namespace native::detail {
13 template<class U>
14 constexpr U bmi1_extract(U value, unsigned start, unsigned length) noexcept {
15 constexpr unsigned width = sizeof(U) * 8;
16 start &= 255u;
17 length &= 255u;
18 if (start >= width) return 0;
19 auto shifted = U(value >> start);
20 return length >= width - start ? shifted : U(shifted & ((U{1} << length) - U{1}));
21 }
22}
23
24namespace native {
30
32 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
34 constexpr std::uint32_t andn(std::uint32_t first, std::uint32_t second) noexcept {
35 if (__builtin_is_constant_evaluated()) {
36 return (~first) & second;
37 } else {
38 return _andn_u32(first, second);
39 }
40 }
41
42 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
43 native_nodiscard native_inline native_const __attribute__((target("bmi")))
44 constexpr std::uint64_t andn(std::uint64_t first, std::uint64_t second) noexcept {
45 if (__builtin_is_constant_evaluated()) {
46 return (~first) & second;
47 } else {
48 return _andn_u64(first, second);
49 }
50 }
51
54 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
55 native_nodiscard native_inline native_const __attribute__((target("bmi")))
56 constexpr std::uint32_t bextr(std::uint32_t value, std::uint32_t control) noexcept {
57 if (__builtin_is_constant_evaluated()) {
58 return detail::bmi1_extract(value, control & 255u, (control >> 8) & 255u);
59 } else {
60 return _bextr2_u32(value, control);
61 }
62 }
63
64 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
65 native_nodiscard native_inline native_const __attribute__((target("bmi")))
66 constexpr std::uint64_t bextr(std::uint64_t value, std::uint32_t control) noexcept {
67 if (__builtin_is_constant_evaluated()) {
68 return detail::bmi1_extract(value, control & 255u, (control >> 8) & 255u);
69 } else {
70 return _bextr2_u64(value, control);
71 }
72 }
73
74 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
75 native_nodiscard native_inline native_const __attribute__((target("bmi")))
76 constexpr std::uint32_t bextr(std::uint32_t value, unsigned start, unsigned length) noexcept {
77 if (__builtin_is_constant_evaluated()) {
78 return detail::bmi1_extract(value, start, length);
79 } else {
80 return _bextr_u32(value, start, length);
81 }
82 }
83
84 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
85 native_nodiscard native_inline native_const __attribute__((target("bmi")))
86 constexpr std::uint64_t bextr(std::uint64_t value, unsigned start, unsigned length) noexcept {
87 if (__builtin_is_constant_evaluated()) {
88 return detail::bmi1_extract(value, start, length);
89 } else {
90 return _bextr_u64(value, start, length);
91 }
92 }
93
95 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
96 native_nodiscard native_inline native_const __attribute__((target("bmi")))
97 constexpr std::uint32_t blsi(std::uint32_t value) noexcept {
98 if (__builtin_is_constant_evaluated()) {
99 return value & (std::uint32_t{0} - value);
100 } else {
101 return _blsi_u32(value);
102 }
103 }
104
105 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
106 native_nodiscard native_inline native_const __attribute__((target("bmi")))
107 constexpr std::uint64_t blsi(std::uint64_t value) noexcept {
108 if (__builtin_is_constant_evaluated()) {
109 return value & (std::uint64_t{0} - value);
110 } else {
111 return _blsi_u64(value);
112 }
113 }
114
116 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
117 native_nodiscard native_inline native_const __attribute__((target("bmi")))
118 constexpr std::uint32_t blsmsk(std::uint32_t value) noexcept {
119 if (__builtin_is_constant_evaluated()) {
120 return value ^ (value - std::uint32_t{1});
121 } else {
122 return _blsmsk_u32(value);
123 }
124 }
125
126 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
127 native_nodiscard native_inline native_const __attribute__((target("bmi")))
128 constexpr std::uint64_t blsmsk(std::uint64_t value) noexcept {
129 if (__builtin_is_constant_evaluated()) {
130 return value ^ (value - std::uint64_t{1});
131 } else {
132 return _blsmsk_u64(value);
133 }
134 }
135
137 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
138 native_nodiscard native_inline native_const __attribute__((target("bmi")))
139 constexpr std::uint32_t blsr(std::uint32_t value) noexcept {
140 if (__builtin_is_constant_evaluated()) {
141 return value & (value - std::uint32_t{1});
142 } else {
143 return _blsr_u32(value);
144 }
145 }
146
147 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
148 native_nodiscard native_inline native_const __attribute__((target("bmi")))
149 constexpr std::uint64_t blsr(std::uint64_t value) noexcept {
150 if (__builtin_is_constant_evaluated()) {
151 return value & (value - std::uint64_t{1});
152 } else {
153 return _blsr_u64(value);
154 }
155 }
156
158 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
159 native_nodiscard native_inline native_const __attribute__((target("bmi")))
160 constexpr std::uint16_t tzcnt(std::uint16_t value) noexcept {
161 if (__builtin_is_constant_evaluated()) {
162 return static_cast<std::uint16_t>(std::countr_zero(value));
163 } else {
164 return _tzcnt_u16(value);
165 }
166 }
167
168 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
169 native_nodiscard native_inline native_const __attribute__((target("bmi")))
170 constexpr std::uint32_t tzcnt(std::uint32_t value) noexcept {
171 if (__builtin_is_constant_evaluated()) {
172 return static_cast<std::uint32_t>(std::countr_zero(value));
173 } else {
174 return _tzcnt_u32(value);
175 }
176 }
177
178 template<isa<x86> Arch> requires(Arch.has(x86_feature::bmi1))
179 native_nodiscard native_inline native_const __attribute__((target("bmi")))
180 constexpr std::uint64_t tzcnt(std::uint64_t value) noexcept {
181 if (__builtin_is_constant_evaluated()) {
182 return static_cast<std::uint64_t>(std::countr_zero(value));
183 } else {
184 return _tzcnt_u64(value);
185 }
186 }
187
189 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
191 consteval std::uint32_t andn(std::uint32_t first, std::uint32_t second) noexcept {
192 return andn<isa<x86>{x86_feature::bmi1}>(first, second);
193 }
194
196 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
198 consteval std::uint64_t andn(std::uint64_t first, std::uint64_t second) noexcept {
199 return andn<isa<x86>{x86_feature::bmi1}>(first, second);
200 }
201
203 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
205 consteval std::uint32_t bextr(std::uint32_t value, std::uint32_t control) noexcept {
206 return bextr<isa<x86>{x86_feature::bmi1}>(value, control);
207 }
208
210 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
212 consteval std::uint64_t bextr(std::uint64_t value, std::uint32_t control) noexcept {
213 return bextr<isa<x86>{x86_feature::bmi1}>(value, control);
214 }
215
217 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
219 consteval std::uint32_t bextr(std::uint32_t value, unsigned start, unsigned length) noexcept {
220 return bextr<isa<x86>{x86_feature::bmi1}>(value, start, length);
221 }
222
224 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
226 consteval std::uint64_t bextr(std::uint64_t value, unsigned start, unsigned length) noexcept {
227 return bextr<isa<x86>{x86_feature::bmi1}>(value, start, length);
228 }
229
231 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
233 consteval std::uint32_t blsi(std::uint32_t value) noexcept {
234 return blsi<isa<x86>{x86_feature::bmi1}>(value);
235 }
236
238 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
240 consteval std::uint64_t blsi(std::uint64_t value) noexcept {
241 return blsi<isa<x86>{x86_feature::bmi1}>(value);
242 }
243
245 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
247 consteval std::uint32_t blsmsk(std::uint32_t value) noexcept {
248 return blsmsk<isa<x86>{x86_feature::bmi1}>(value);
249 }
250
252 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
254 consteval std::uint64_t blsmsk(std::uint64_t value) noexcept {
255 return blsmsk<isa<x86>{x86_feature::bmi1}>(value);
256 }
257
259 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
261 consteval std::uint32_t blsr(std::uint32_t value) noexcept {
262 return blsr<isa<x86>{x86_feature::bmi1}>(value);
263 }
264
266 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
268 consteval std::uint64_t blsr(std::uint64_t value) noexcept {
269 return blsr<isa<x86>{x86_feature::bmi1}>(value);
270 }
271
273 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
275 consteval std::uint16_t tzcnt(std::uint16_t value) noexcept {
276 return tzcnt<isa<x86>{x86_feature::bmi1}>(value);
277 }
278
280 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
282 consteval std::uint32_t tzcnt(std::uint32_t value) noexcept {
283 return tzcnt<isa<x86>{x86_feature::bmi1}>(value);
284 }
285
287 template<isa<x86> Arch> requires(!Arch.has(x86_feature::bmi1))
289 consteval std::uint64_t tzcnt(std::uint64_t value) noexcept {
290 return tzcnt<isa<x86>{x86_feature::bmi1}>(value);
291 }
292
294}
295#endif
Compiler attributes for host code, with shader-safe shared modifiers.
#define native_inline
inline [[always_inline]]
Definition attributes.h:212
#define native_nodiscard
C++17 [[nodiscard]].
Definition attributes.h:189
#define native_const
[[const]] is not const
Definition attributes.h:108
constexpr std::uint32_t andn(std::uint32_t first, std::uint32_t second) noexcept
ANDN: complement the first operand, then AND with the second.
Definition bmi1.h:34
constexpr std::uint32_t bextr(std::uint32_t value, std::uint32_t control) noexcept
Definition bmi1.h:56
constexpr std::uint16_t tzcnt(std::uint16_t value) noexcept
TZCNT: count low zero bits; zero returns the operand width, including 16-bit operands.
Definition bmi1.h:160
constexpr std::uint32_t blsmsk(std::uint32_t value) noexcept
BLSMSK: set every bit through the lowest set bit; zero produces all ones.
Definition bmi1.h:118
constexpr std::uint32_t blsr(std::uint32_t value) noexcept
BLSR: clear the lowest set bit; zero remains zero.
Definition bmi1.h:139
constexpr std::uint32_t blsi(std::uint32_t value) noexcept
BLSI: retain only the lowest set bit; zero remains zero.
Definition bmi1.h:97
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
constexpr int target
First matching requirement, with every later choice checked for shadowing.
Definition isa.h:396
Standard-library adaptations documented here for SIMD value types.