native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
adx.h
1// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0
2#pragma once
3
4#include "native/config.h"
5#include "native/attributes.h"
6#include "native/isa.h"
7#include <cstdint>
8#if NATIVE_HOST_X86
9#include <immintrin.h>
10
11namespace native::detail::x86_adx {
12 template<class U>
13 constexpr std::uint8_t add(std::uint8_t carry, U a, U b, U * result) noexcept {
14 auto first = static_cast<U>(a + b);
15 auto overflow = first < a;
16 auto sum = static_cast<U>(first + (carry != 0));
17 *result = sum;
18 return static_cast<std::uint8_t>(overflow || sum < first);
19 }
20
21 template<isa<x86> Arch> requires(Arch.has(x86_feature::adx))
23 std::uint8_t addcarryx(std::uint8_t carry, std::uint32_t a, std::uint32_t b, std::uint32_t * result) noexcept {
24 return _addcarryx_u32(carry, a, b, result);
25 }
26
27 template<isa<x86> Arch> requires(Arch.has(x86_feature::adx))
29 std::uint8_t addcarryx(std::uint8_t carry, std::uint64_t a, std::uint64_t b, std::uint64_t * result) noexcept {
30 // The intrinsic output uses unsigned long long even on LP64 platforms.
31 unsigned long long sum;
32 auto next = _addcarryx_u64(carry, a, b, &sum);
33 *result = sum;
34 return next;
35 }
36
37 template<isa<x86> Arch, class... Args>
38 void addcarryx(Args...) = delete;
39}
40
41namespace native {
51
53 template<isa<x86> Arch> requires(Arch.has(x86_feature::adx))
55 constexpr std::uint8_t addcarryx(
56 std::uint8_t carry, std::uint32_t a, std::uint32_t b, std::uint32_t * result) noexcept {
57 if consteval {
58 return detail::x86_adx::add(carry, a, b, result);
59 } else {
60 return detail::x86_adx::addcarryx<Arch>(carry, a, b, result);
61 }
62 }
63
65 template<isa<x86> Arch> requires(Arch.has(x86_feature::adx))
67 constexpr std::uint8_t addcarryx(
68 std::uint8_t carry, std::uint64_t a, std::uint64_t b, std::uint64_t * result) noexcept {
69 if consteval {
70 return detail::x86_adx::add(carry, a, b, result);
71 } else {
72 return detail::x86_adx::addcarryx<Arch>(carry, a, b, result);
73 }
74 }
75
77 template<isa<x86> Arch> requires(!Arch.has(x86_feature::adx))
78 native_nodiscard consteval std::uint8_t addcarryx(
79 std::uint8_t carry, std::uint32_t a, std::uint32_t b, std::uint32_t * result) noexcept {
80 return detail::x86_adx::add(carry, a, b, result);
81 }
82
84 template<isa<x86> Arch> requires(!Arch.has(x86_feature::adx))
85 native_nodiscard consteval std::uint8_t addcarryx(
86 std::uint8_t carry, std::uint64_t a, std::uint64_t b, std::uint64_t * result) noexcept {
87 return detail::x86_adx::add(carry, a, b, result);
88 }
89
91}
92#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_target(x)
this indicates a required feature set for the current multiversioned function.
Definition attributes.h:476
constexpr std::uint8_t addcarryx(std::uint8_t carry, std::uint32_t a, std::uint32_t b, std::uint32_t *result) noexcept
Add 32-bit operands with carry, writing the modular result.
Definition adx.h:55
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
Standard-library adaptations documented here for SIMD value types.