4#include "native/isa_import.h"
8#include "native/targets.h"
31 concept waiter =
requires (
volatile void * p, std::uint32_t t) {
48 noexcept(
noexcept(!f(p)) &&
noexcept(W::monitor(p)) &&
noexcept(W::mwait(0)))
native_blocking {
49 [[assume(W::supported)]];
59 using timer_t = std::uint64_t;
62 [[gnu::target(
"mwaitx")]]
static void monitor(
volatile void * p)
noexcept;
67 static const bool supported;
73 using timer_t = std::uint64_t;
76 [[gnu::target(
"waitpkg")]]
static void monitor(
volatile void * p)
noexcept;
79 [[gnu::target(
"waitpkg")]]
static std::uint8_t
mwait(std::uint64_t timer = 0)
noexcept native_blocking;
81 static const bool supported;
88 template<isa<x86> Arch = NATIVE_BA
SELINE,
unsigned Control = 1>
89 requires(Arch.has(x86_feature::waitpkg) && Control < 2)
92 return __builtin_ia32_tpause(Control, std::uint32_t(deadline >> 32),
93 std::uint32_t(deadline));
98 using timer_t = std::uint64_t;
104 inline static constinit bool supported =
true;
116 noexcept(
noexcept(k.template operator()<
mwaitx>()) &&
117 noexcept(k.template
operator()<
umwait>()) &&
noexcept(k.template
operator()<
spin>())) {
118 if (mwaitx::supported)
return k.template operator()<
mwaitx>();
119 else if (umwait::supported)
return k.template operator()<
umwait>();
120 else return k.template operator()<
spin>();
130 _mm_monitorx(
const_cast<void *
>(p), 0, 0);
133 _mm_mwaitx(0, 0, timer);
136 _umonitor(
const_cast<void *
>(p));
139 return _umwait(1, timer);
147 const bool mwaitx::supported = classify_isa(wait_capabilities, x86_feature::mwaitx).admitted();
148 const bool umwait::supported = classify_isa(wait_capabilities, x86_feature::waitpkg).admitted();
Compiler attributes for host code, with shader-safe shared modifiers.
some way to wait for a value to change
#define native_artificial
[[artificial]].
#define native_inline
inline [[always_inline]]
#define native_flatten
portable [[flatten]]
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
void wait_until(volatile auto *p, auto f) noexcept(noexcept(!f(p)) &&noexcept(W::monitor(p)) &&noexcept(W::mwait(0))) native_blocking
Wait until a predicate holds about a given memory location.
std::uint8_t tpause(std::uint64_t deadline) noexcept native_blocking
auto with_waiter(auto k) noexcept(noexcept(k.template operator()<mwaitx >()) &&noexcept(k.template operator()<umwait >()) &&noexcept(k.template operator()<spin >()))
finds an appropriate waiter for the current CPU Prefer MWAITX, then WAITPKG, otherwise PAUSE....
static void mwait(std::uint32_t timer=0) noexcept native_blocking
static void monitor(volatile void *p) noexcept
static void monitor(volatile void *p) noexcept
static std::uint8_t mwait(std::uint64_t timer=0) noexcept native_blocking
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
x86_capabilities observe_x86_capabilities() noexcept
Capture CPUID and, only with XSAVE and OSXSAVE, XCR0. No ISA profile required.
Standard-library adaptations documented here for SIMD value types.
waiter using the MONITORX/MWAITX instruction feature
A universally supported x86 spin waiter using PAUSE; monitor is a no-op.
static void mwait(std::uint32_t=0) noexcept native_blocking
Issue one PAUSE, ignoring the timer; no sleep duration or memory ordering is promised.
static void monitor(volatile void *) noexcept
Ignore the address; PAUSE waiting does not arm a hardware monitor.
waiter using the WAITPKG instruction feature