native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
native.arm.sm3.ccm
1// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0
2module;
3#include "native/isa_import.h"
4#include "native/arm/detail/constant_lanes.h"
5#include "native/config.h"
6#include "native/attributes.h"
7#include "native/isa.h"
8#include <cstdint>
9#if NATIVE_HOST_NEON
10#include <arm_neon.h>
11#endif
12#include "native/targets.h"
13export module native.arm.sm3;
14export import native.arm.features;
15export import native.simd;
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);
19 }
20
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);
27 }
28
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;
42 if constexpr (Second)
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);
46 }
47
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);
50 }
51
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);
54 }
55
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);
58 }
59
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);
62 }
63
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);
73 }
74
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);
84 }
85} // namespace native::detail::arm_sm3_constant
86
88#if NATIVE_HOST_NEON
89
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);
96 }
97
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);
103 }
104
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);
110 }
111
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);
117 }
118
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);
124 }
125
126 template<isa<arm> Arch>
127 requires(Arch.has(arm_feature::sm3))
128 native_nodiscard native_inline native_const native_target("sm4") uint32x4_t sm3partw1(
129 uint32x4_t a, uint32x4_t b, uint32x4_t c) noexcept {
130 return vsm3partw1q_u32(a, b, c);
131 }
132
133 template<isa<arm> Arch>
134 requires(Arch.has(arm_feature::sm3))
135 native_nodiscard native_inline native_const native_target("sm4") uint32x4_t sm3partw2(
136 uint32x4_t a, uint32x4_t b, uint32x4_t c) noexcept {
137 return vsm3partw2q_u32(a, b, c);
138 }
139
140} // namespace native::detail::arm_sm3
141#endif
143
144#if NATIVE_HOST_NEON || defined(NATIVE_DOXYGEN)
145export namespace native {
154
156 template<isa<arm> Arch>
157 requires(Arch.has(arm_feature::sm3))
159 native_target("sm4") constexpr simd<std::uint32_t, 4, Arch>
160 sm3ss1(simd<std::uint32_t, 4, Arch> a, simd<std::uint32_t, 4, Arch> b,
161 simd<std::uint32_t, 4, Arch> c) noexcept {
162 if consteval {
163 return detail::arm_sm3_constant::sm3ss1(a, b, c);
164 } else {
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()));
169 __builtin_bit_cast(typename simd<std::uint32_t, 4, Arch>::native_type, result));
170 }
171 }
172
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);
179 }
180
183 template<isa<arm> Arch, int Lane>
184 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
186 native_target("sm4") constexpr simd<std::uint32_t, 4, Arch>
187 sm3tt1a(simd<std::uint32_t, 4, Arch> state, simd<std::uint32_t, 4, Arch> ss1,
188 simd<std::uint32_t, 4, Arch> words) noexcept {
189 if consteval {
190 return detail::arm_sm3_constant::sm3tt1a<Lane>(state, ss1, words);
191 } else {
192 auto result =
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()));
197 __builtin_bit_cast(typename simd<std::uint32_t, 4, Arch>::native_type, result));
198 }
199 }
200
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>); })
207 simd<std::uint32_t, 4, Arch> words) noexcept {
208 return detail::arm_sm3_constant::sm3tt1a<Lane>(state, ss1, words);
209 }
210
213 template<isa<arm> Arch, int Lane>
214 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
216 native_target("sm4") constexpr simd<std::uint32_t, 4, Arch>
217 sm3tt1b(simd<std::uint32_t, 4, Arch> state, simd<std::uint32_t, 4, Arch> ss1,
218 simd<std::uint32_t, 4, Arch> words) noexcept {
219 if consteval {
220 return detail::arm_sm3_constant::sm3tt1b<Lane>(state, ss1, words);
221 } else {
222 auto result =
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()));
227 __builtin_bit_cast(typename simd<std::uint32_t, 4, Arch>::native_type, result));
228 }
229 }
230
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>); })
237 simd<std::uint32_t, 4, Arch> words) noexcept {
238 return detail::arm_sm3_constant::sm3tt1b<Lane>(state, ss1, words);
239 }
240
243 template<isa<arm> Arch, int Lane>
244 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
246 native_target("sm4") constexpr simd<std::uint32_t, 4, Arch>
247 sm3tt2a(simd<std::uint32_t, 4, Arch> state, simd<std::uint32_t, 4, Arch> ss1,
248 simd<std::uint32_t, 4, Arch> words) noexcept {
249 if consteval {
250 return detail::arm_sm3_constant::sm3tt2a<Lane>(state, ss1, words);
251 } else {
252 auto result =
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()));
257 __builtin_bit_cast(typename simd<std::uint32_t, 4, Arch>::native_type, result));
258 }
259 }
260
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>); })
267 simd<std::uint32_t, 4, Arch> words) noexcept {
268 return detail::arm_sm3_constant::sm3tt2a<Lane>(state, ss1, words);
269 }
270
273 template<isa<arm> Arch, int Lane>
274 requires(Arch.has(arm_feature::sm3) && Lane >= 0 && Lane < 4)
276 native_target("sm4") constexpr simd<std::uint32_t, 4, Arch>
277 sm3tt2b(simd<std::uint32_t, 4, Arch> state, simd<std::uint32_t, 4, Arch> ss1,
278 simd<std::uint32_t, 4, Arch> words) noexcept {
279 if consteval {
280 return detail::arm_sm3_constant::sm3tt2b<Lane>(state, ss1, words);
281 } else {
282 auto result =
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()));
287 __builtin_bit_cast(typename simd<std::uint32_t, 4, Arch>::native_type, result));
288 }
289 }
290
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>); })
297 simd<std::uint32_t, 4, Arch> words) noexcept {
298 return detail::arm_sm3_constant::sm3tt2b<Lane>(state, ss1, words);
299 }
300
302 template<isa<arm> Arch>
303 requires(Arch.has(arm_feature::sm3))
305 native_target("sm4") constexpr simd<std::uint32_t, 4, Arch>
306 sm3partw1(simd<std::uint32_t, 4, Arch> a, simd<std::uint32_t, 4, Arch> b,
307 simd<std::uint32_t, 4, Arch> c) noexcept {
308 if consteval {
309 return detail::arm_sm3_constant::sm3partw1(a, b, c);
310 } else {
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()));
315 __builtin_bit_cast(typename simd<std::uint32_t, 4, Arch>::native_type, result));
316 }
317 }
318
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);
325 }
326
328 template<isa<arm> Arch>
329 requires(Arch.has(arm_feature::sm3))
331 native_target("sm4") constexpr simd<std::uint32_t, 4, Arch>
332 sm3partw2(simd<std::uint32_t, 4, Arch> a, simd<std::uint32_t, 4, Arch> b,
333 simd<std::uint32_t, 4, Arch> c) noexcept {
334 if consteval {
335 return detail::arm_sm3_constant::sm3partw2(a, b, c);
336 } else {
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()));
341 __builtin_bit_cast(typename simd<std::uint32_t, 4, Arch>::native_type, result));
342 }
343 }
344
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);
351 }
352
354} // namespace native
355#endif
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]]
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
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
Definition attributes.h:476
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.