3#include "native/isa_import.h"
4#include "native/arm/detail/constant_lanes.h"
5#include "native/config.h"
12#include "native/targets.h"
16namespace native::detail::arm_sm3_constant {
17 constexpr std::uint32_t p1(std::uint32_t value)
noexcept {
18 return value ^ std::rotl(value, 15) ^ std::rotl(value, 23);
21 template<
class V>
constexpr V sm3ss1(V a, V b, V c)
noexcept {
22 auto x = arm_constant::lanes(a);
23 auto y = arm_constant::lanes(b);
24 auto z = arm_constant::lanes(c);
25 std::array<std::uint32_t, 4> result{0, 0, 0, std::rotl(std::rotl(x[3], 12) + y[3] + z[3], 7)};
26 return arm_constant::pack<V>(result);
29 template<
int Lane,
bool Second,
bool Late,
class V>
30 constexpr V round(V state, V ss1, V words)
noexcept {
31 auto x = arm_constant::lanes(state);
32 auto s = arm_constant::lanes(ss1)[3];
33 auto word = arm_constant::lanes(words)[Lane];
34 auto boolean = x[3] ^ x[2] ^ x[1];
35 if constexpr (Late && Second)
36 boolean = (x[3] & x[2]) | (~x[3] & x[1]);
37 else if constexpr (Late)
38 boolean = (x[3] & x[2]) | (x[3] & x[1]) | (x[2] & x[1]);
39 if constexpr (!Second)
40 s ^= std::rotl(x[3], 12);
41 auto next =
boolean + x[0] + s + word;
43 next ^= std::rotl(next, 9) ^ std::rotl(next, 17);
44 std::array<std::uint32_t, 4> result{x[1], std::rotl(x[2], Second ? 19 : 9), x[3], next};
45 return arm_constant::pack<V>(result);
48 template<
int Lane,
class V>
constexpr V sm3tt1a(V a, V b, V c)
noexcept {
49 return round<Lane, false, false>(a, b, c);
52 template<
int Lane,
class V>
constexpr V sm3tt1b(V a, V b, V c)
noexcept {
53 return round<Lane, false, true>(a, b, c);
56 template<
int Lane,
class V>
constexpr V sm3tt2a(V a, V b, V c)
noexcept {
57 return round<Lane, true, false>(a, b, c);
60 template<
int Lane,
class V>
constexpr V sm3tt2b(V a, V b, V c)
noexcept {
61 return round<Lane, true, true>(a, b, c);
64 template<
class V>
constexpr V sm3partw1(V a, V b, V c)
noexcept {
65 auto x = arm_constant::lanes(a);
66 auto y = arm_constant::lanes(b);
67 auto z = arm_constant::lanes(c);
68 std::array<std::uint32_t, 4> result{};
69 for (
unsigned i = 0; i < 3; ++i)
70 result[i] = p1(x[i] ^ y[i] ^ std::rotl(z[i + 1], 15));
71 result[3] = p1(x[3] ^ y[3] ^ std::rotl(result[0], 15));
72 return arm_constant::pack<V>(result);
75 template<
class V>
constexpr V sm3partw2(V a, V b, V c)
noexcept {
76 auto x = arm_constant::lanes(a);
77 auto y = arm_constant::lanes(b);
78 auto z = arm_constant::lanes(c);
79 auto first = y[0] ^ std::rotl(z[0], 7);
80 for (
unsigned i = 0; i < 4; ++i)
81 x[i] ^= y[i] ^ std::rotl(z[i], 7);
82 x[3] ^= p1(std::rotl(first, 15));
83 return arm_constant::pack<V>(x);
90namespace native::detail::arm_sm3 {
91 template<isa<arm> Arch>
92 requires(Arch.has(arm_feature::sm3))
94 uint32x4_t a, uint32x4_t b, uint32x4_t c) noexcept {
95 return vsm3ss1q_u32(a, b, c);
98 template<isa<arm> Arch,
int Lane>
99 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
101 uint32x4_t state, uint32x4_t ss1, uint32x4_t words) noexcept {
102 return vsm3tt1aq_u32(state, ss1, words, Lane);
105 template<isa<arm> Arch,
int Lane>
106 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
108 uint32x4_t state, uint32x4_t ss1, uint32x4_t words) noexcept {
109 return vsm3tt1bq_u32(state, ss1, words, Lane);
112 template<isa<arm> Arch,
int Lane>
113 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
115 uint32x4_t state, uint32x4_t ss1, uint32x4_t words) noexcept {
116 return vsm3tt2aq_u32(state, ss1, words, Lane);
119 template<isa<arm> Arch,
int Lane>
120 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
122 uint32x4_t state, uint32x4_t ss1, uint32x4_t words) noexcept {
123 return vsm3tt2bq_u32(state, ss1, words, Lane);
126 template<isa<arm> Arch>
127 requires(Arch.has(arm_feature::sm3))
129 uint32x4_t a, uint32x4_t b, uint32x4_t c) noexcept {
130 return vsm3partw1q_u32(a, b, c);
133 template<isa<arm> Arch>
134 requires(Arch.has(arm_feature::sm3))
136 uint32x4_t a, uint32x4_t b, uint32x4_t c) noexcept {
137 return vsm3partw2q_u32(a, b, c);
144#if NATIVE_HOST_NEON || defined(NATIVE_DOXYGEN)
156 template<isa<arm> Arch>
157 requires(Arch.has(arm_feature::sm3))
161 simd<
std::uint32_t, 4, Arch> c) noexcept {
163 return detail::arm_sm3_constant::sm3ss1(a, b, c);
165 auto result = detail::arm_sm3::sm3ss1<Arch>(__builtin_bit_cast(uint32x4_t, a.to_native()),
166 __builtin_bit_cast(uint32x4_t, b.to_native()),
167 __builtin_bit_cast(uint32x4_t, c.to_native()));
174 template<isa<arm> Arch>
175 requires(!Arch.has(arm_feature::sm3) &&
requires {
sizeof(simd<std::uint32_t, 4, Arch>); })
178 return detail::arm_sm3_constant::sm3ss1(a, b, c);
183 template<isa<arm> Arch,
int Lane>
184 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
188 simd<
std::uint32_t, 4, Arch> words) noexcept {
190 return detail::arm_sm3_constant::sm3tt1a<Lane>(state, ss1, words);
193 detail::arm_sm3::sm3tt1a<Arch, Lane>(__builtin_bit_cast(uint32x4_t, state.to_native()),
194 __builtin_bit_cast(uint32x4_t, ss1.to_native()),
195 __builtin_bit_cast(uint32x4_t, words.to_native()));
202 template<isa<arm> Arch,
int Lane>
203 requires(!Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4 &&
204 requires {
sizeof(simd<std::uint32_t, 4, Arch>); })
208 return detail::arm_sm3_constant::sm3tt1a<Lane>(state, ss1, words);
213 template<isa<arm> Arch,
int Lane>
214 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
218 simd<
std::uint32_t, 4, Arch> words) noexcept {
220 return detail::arm_sm3_constant::sm3tt1b<Lane>(state, ss1, words);
223 detail::arm_sm3::sm3tt1b<Arch, Lane>(__builtin_bit_cast(uint32x4_t, state.to_native()),
224 __builtin_bit_cast(uint32x4_t, ss1.to_native()),
225 __builtin_bit_cast(uint32x4_t, words.to_native()));
232 template<isa<arm> Arch,
int Lane>
233 requires(!Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4 &&
234 requires {
sizeof(simd<std::uint32_t, 4, Arch>); })
238 return detail::arm_sm3_constant::sm3tt1b<Lane>(state, ss1, words);
243 template<isa<arm> Arch,
int Lane>
244 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
248 simd<
std::uint32_t, 4, Arch> words) noexcept {
250 return detail::arm_sm3_constant::sm3tt2a<Lane>(state, ss1, words);
253 detail::arm_sm3::sm3tt2a<Arch, Lane>(__builtin_bit_cast(uint32x4_t, state.to_native()),
254 __builtin_bit_cast(uint32x4_t, ss1.to_native()),
255 __builtin_bit_cast(uint32x4_t, words.to_native()));
262 template<isa<arm> Arch,
int Lane>
263 requires(!Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4 &&
264 requires {
sizeof(simd<std::uint32_t, 4, Arch>); })
268 return detail::arm_sm3_constant::sm3tt2a<Lane>(state, ss1, words);
273 template<isa<arm> Arch,
int Lane>
274 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
278 simd<
std::uint32_t, 4, Arch> words) noexcept {
280 return detail::arm_sm3_constant::sm3tt2b<Lane>(state, ss1, words);
283 detail::arm_sm3::sm3tt2b<Arch, Lane>(__builtin_bit_cast(uint32x4_t, state.to_native()),
284 __builtin_bit_cast(uint32x4_t, ss1.to_native()),
285 __builtin_bit_cast(uint32x4_t, words.to_native()));
292 template<isa<arm> Arch,
int Lane>
293 requires(!Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4 &&
294 requires {
sizeof(simd<std::uint32_t, 4, Arch>); })
298 return detail::arm_sm3_constant::sm3tt2b<Lane>(state, ss1, words);
302 template<isa<arm> Arch>
303 requires(Arch.has(arm_feature::sm3))
307 simd<
std::uint32_t, 4, Arch> c) noexcept {
309 return detail::arm_sm3_constant::sm3partw1(a, b, c);
311 auto result = detail::arm_sm3::sm3partw1<Arch>(__builtin_bit_cast(uint32x4_t, a.to_native()),
312 __builtin_bit_cast(uint32x4_t, b.to_native()),
313 __builtin_bit_cast(uint32x4_t, c.to_native()));
320 template<isa<arm> Arch>
321 requires(!Arch.has(arm_feature::sm3) &&
requires {
sizeof(simd<std::uint32_t, 4, Arch>); })
324 return detail::arm_sm3_constant::sm3partw1(a, b, c);
328 template<isa<arm> Arch>
329 requires(Arch.has(arm_feature::sm3))
333 simd<
std::uint32_t, 4, Arch> c) noexcept {
335 return detail::arm_sm3_constant::sm3partw2(a, b, c);
337 auto result = detail::arm_sm3::sm3partw2<Arch>(__builtin_bit_cast(uint32x4_t, a.to_native()),
338 __builtin_bit_cast(uint32x4_t, b.to_native()),
339 __builtin_bit_cast(uint32x4_t, c.to_native()));
346 template<isa<arm> Arch>
347 requires(!Arch.has(arm_feature::sm3) &&
requires {
sizeof(simd<std::uint32_t, 4, Arch>); })
350 return detail::arm_sm3_constant::sm3partw2(a, b, c);
Compiler attributes for host code, with shader-safe shared modifiers.
constexpr simd< std::uint32_t, 4, Arch > sm3ss1(simd< std::uint32_t, 4, Arch > a, simd< std::uint32_t, 4, Arch > b, simd< std::uint32_t, 4, Arch > c) noexcept
Rotate and add the lane-three inputs; return SS1 in lane three and zero elsewhere.
constexpr simd< std::uint32_t, 4, Arch > sm3tt1b(simd< std::uint32_t, 4, Arch > state, simd< std::uint32_t, 4, Arch > ss1, simd< std::uint32_t, 4, Arch > words) noexcept
constexpr simd< std::uint32_t, 4, Arch > sm3partw1(simd< std::uint32_t, 4, Arch > a, simd< std::uint32_t, 4, Arch > b, simd< std::uint32_t, 4, Arch > c) noexcept
Compute the first four-word SM3 message-schedule update, including lane-zero feedback.
constexpr simd< std::uint32_t, 4, Arch > sm3tt1a(simd< std::uint32_t, 4, Arch > state, simd< std::uint32_t, 4, Arch > ss1, simd< std::uint32_t, 4, Arch > words) noexcept
constexpr simd< std::uint32_t, 4, Arch > sm3partw2(simd< std::uint32_t, 4, Arch > a, simd< std::uint32_t, 4, Arch > b, simd< std::uint32_t, 4, Arch > c) noexcept
Finish the four-word SM3 schedule update with the remaining XOR and rotation terms.
constexpr simd< std::uint32_t, 4, Arch > sm3tt2b(simd< std::uint32_t, 4, Arch > state, simd< std::uint32_t, 4, Arch > ss1, simd< std::uint32_t, 4, Arch > words) noexcept
constexpr simd< std::uint32_t, 4, Arch > sm3tt2a(simd< std::uint32_t, 4, Arch > state, simd< std::uint32_t, 4, Arch > ss1, simd< std::uint32_t, 4, Arch > words) noexcept
#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.
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.