3#include "native/isa_import.h"
4#include "native/config.h"
10#include "native/x86/detail/constant_lanes.h"
15namespace native::detail::x86_sm3_constant {
16 template<
class V>
constexpr V sm3msg1(V a, V b, V c)
noexcept {
17 auto x = x86_constant::lanes(a), y = x86_constant::lanes(b), z = x86_constant::lanes(c);
18 for (
unsigned i = 0; i < 4; ++i) {
20 if (i < 3) t ^= std::rotl(y[i], 15);
21 x[i] = t ^ std::rotl(t, 15) ^ std::rotl(t, 23);
23 return x86_constant::pack<V>(x);
25 template<
class V>
constexpr V sm3msg2(V a, V b, V c)
noexcept {
26 auto x = x86_constant::lanes(a), y = x86_constant::lanes(b), z = x86_constant::lanes(c);
27 for (
unsigned i = 0; i < 4; ++i) x[i] ^= std::rotl(y[i], 7) ^ z[i];
28 x[3] ^= std::rotl(x[0], 6) ^ std::rotl(x[0], 15) ^ std::rotl(x[0], 30);
29 return x86_constant::pack<V>(x);
31 template<
unsigned Imm8,
class V>
constexpr V sm3rnds2(V cdgh, V abef, V message)
noexcept {
32 auto x = x86_constant::lanes(cdgh), y = x86_constant::lanes(abef);
33 auto words = x86_constant::lanes(message);
34 auto a = y[3], b = y[2], c = std::rotl(x[3], 9), d = std::rotl(x[2], 9);
35 auto e = y[1], f = y[0], g = std::rotl(x[1], 19), h = std::rotl(x[0], 19);
36 constexpr unsigned round = Imm8 & 62;
37 auto k = std::rotl(std::uint32_t(round < 16 ? 0x79cc4519 : 0x7a879d8a),
int(round));
38 for (
unsigned i = 0; i < 2; ++i) {
39 auto ss1 = std::rotl(std::rotl(a, 12) + e + k, 7);
40 auto ss2 = ss1 ^ std::rotl(a, 12);
41 auto ff = round < 16 ? a ^ b ^ c : (a & b) | (a & c) | (b & c);
42 auto gg = round < 16 ? e ^ f ^ g : (e & f) | (~e & g);
43 auto tt1 = ff + d + ss2 + (words[i] ^ words[i + 2]);
44 auto tt2 = gg + h + ss1 + words[i];
45 d = c; c = std::rotl(b, 9); b = a; a = tt1;
46 h = g; g = std::rotl(f, 19); f = e;
47 e = tt2 ^ std::rotl(tt2, 9) ^ std::rotl(tt2, 17);
50 return x86_constant::pack<V>(std::array{f, e, b, a});
63 template<isa<x86> Arch>
64 requires(Arch.has(x86_feature::sm3) && Arch.has(x86_feature::avx))
66 constexpr
simd<
std::uint32_t, 4, Arch>
sm3msg1(
simd<
std::uint32_t, 4, Arch> a,
simd<
std::uint32_t, 4, Arch> b,
simd<
std::uint32_t, 4, Arch> c) noexcept {
67 if consteval {
return detail::x86_sm3_constant::sm3msg1(a, b, c); }
72 template<isa<x86> Arch>
73 requires(!(Arch.has(x86_feature::sm3) && Arch.has(x86_feature::avx)) &&
74 requires { sizeof(simd<std::uint32_t, 4, Arch>); })
75 native_nodiscard consteval simd<std::uint32_t, 4, Arch> sm3msg1(
simd<std::uint32_t, 4, Arch> a,
simd<std::uint32_t, 4, Arch> b,
simd<std::uint32_t, 4, Arch> c)
noexcept {
76 return detail::x86_sm3_constant::sm3msg1(a, b, c);
80 template<isa<x86> Arch>
81 requires(Arch.has(x86_feature::sm3) && Arch.has(x86_feature::avx))
83 constexpr simd<std::uint32_t, 4, Arch> sm3msg2(
simd<std::uint32_t, 4, Arch> a,
simd<std::uint32_t, 4, Arch> b,
simd<std::uint32_t, 4, Arch> c)
noexcept {
84 if consteval {
return detail::x86_sm3_constant::sm3msg2(a, b, c); }
89 template<isa<x86> Arch>
90 requires(!(Arch.has(x86_feature::sm3) && Arch.has(x86_feature::avx)) &&
91 requires { sizeof(simd<std::uint32_t, 4, Arch>); })
92 native_nodiscard consteval simd<std::uint32_t, 4, Arch> sm3msg2(
simd<std::uint32_t, 4, Arch> a,
simd<std::uint32_t, 4, Arch> b,
simd<std::uint32_t, 4, Arch> c)
noexcept {
93 return detail::x86_sm3_constant::sm3msg2(a, b, c);
97 template<isa<x86> Arch,
unsigned Imm8>
98 requires(Arch.has(x86_feature::sm3) && Arch.has(x86_feature::avx) && Imm8 <= 255)
100 constexpr simd<std::uint32_t, 4, Arch> sm3rnds2(
simd<std::uint32_t, 4, Arch> a,
simd<std::uint32_t, 4, Arch> b,
simd<std::uint32_t, 4, Arch> c)
noexcept {
101 if consteval {
return detail::x86_sm3_constant::sm3rnds2<Imm8>(a, b, c); }
106 template<isa<x86> Arch,
unsigned Imm8>
107 requires(!(Arch.has(x86_feature::sm3) && Arch.has(x86_feature::avx)) && Imm8 <= 255 &&
108 requires { sizeof(simd<std::uint32_t, 4, Arch>); })
109 native_nodiscard consteval simd<std::uint32_t, 4, Arch> sm3rnds2(
simd<std::uint32_t, 4, Arch> a,
simd<std::uint32_t, 4, Arch> b,
simd<std::uint32_t, 4, Arch> c)
noexcept {
110 return detail::x86_sm3_constant::sm3rnds2<Imm8>(a, b, c);
114 template<isa<x86> Arch,
class... Args>
void sm3msg1(Args...) =
delete;
117 template<isa<x86> Arch,
class... Args>
void sm3msg2(Args...) =
delete;
120 template<isa<x86> Arch,
unsigned Imm8,
class... Args>
void sm3rnds2(Args...) =
delete;
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
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
constexpr simd< std::uint32_t, 4, Arch > sm3msg2(simd< std::uint32_t, 4, Arch > a, simd< std::uint32_t, 4, Arch > b, simd< std::uint32_t, 4, Arch > c) noexcept
Final SM3 schedule step.
constexpr simd< std::uint32_t, 4, Arch > sm3msg1(simd< std::uint32_t, 4, Arch > a, simd< std::uint32_t, 4, Arch > b, simd< std::uint32_t, 4, Arch > c) noexcept
First SM3 schedule step.
constexpr simd< std::uint32_t, 4, Arch > sm3rnds2(simd< std::uint32_t, 4, Arch > a, simd< std::uint32_t, 4, Arch > b, simd< std::uint32_t, 4, Arch > c) noexcept
Two SM3 rounds; Imm8 is masked with 0x3e. a holds unrotated CDGH and b holds ABEF.
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
Standard-library adaptations documented here for SIMD value types.
Omitted architecture arguments use the native.simd provider's baseline.