aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2024-08-10 17:40:37 +0200
committerGitHub <noreply@github.com>2024-08-10 17:40:37 +0200
commitc0d829e588c5d25ee0fc0ff3212658c92c0fb0a8 (patch)
tree39811fc48570ef219326fb23b2571ae27c55131a /src
parentf148aa65dfe587e7b5d2f48b5005be670788dbe6 (diff)
parent23c95fa1b64f35ba56594acc0bf06962647c4ba0 (diff)
downloadnissy-core-c0d829e588c5d25ee0fc0ff3212658c92c0fb0a8.tar.gz
nissy-core-c0d829e588c5d25ee0fc0ff3212658c92c0fb0a8.zip
Merge pull request #1 from enricotenuti/master
cube_neon ver1
Diffstat (limited to 'src')
-rw-r--r--src/cube.c2
-rw-r--r--src/cube_neon.h377
2 files changed, 376 insertions, 3 deletions
diff --git a/src/cube.c b/src/cube.c
index 1f8711c..e8dedec 100644
--- a/src/cube.c
+++ b/src/cube.c
@@ -27,6 +27,8 @@ void (*nissy_log)(const char *, ...);
27#include <immintrin.h> 27#include <immintrin.h>
28#include "cube_avx2.h" 28#include "cube_avx2.h"
29#elif defined(CUBE_NEON) 29#elif defined(CUBE_NEON)
30#include <stdlib.h>
31#include <arm_neon.h>
30#include "cube_neon.h" 32#include "cube_neon.h"
31#else 33#else
32#include <stdlib.h> /* TODO: check if can be removed */ 34#include <stdlib.h> /* TODO: check if can be removed */
diff --git a/src/cube_neon.h b/src/cube_neon.h
index 434d6b5..23e5565 100644
--- a/src/cube_neon.h
+++ b/src/cube_neon.h
@@ -1,6 +1,377 @@
1/* TODO! */ 1// cube_t
2 2typedef struct
3typedef struct { 3{
4 uint8x16_t corner; 4 uint8x16_t corner;
5 uint8x16_t edge; 5 uint8x16_t edge;
6} cube_t; 6} cube_t;
7
8#define _co2_neon vdupq_n_u8(0x60)
9#define _cocw_neon vdupq_n_u8(0x20)
10#define _cp_neon vdupq_n_u8(0x07)
11#define _ep_neon vcombine_u8(vdupq_n_u8(0x0F), vdupq_n_u8(0x0F))
12#define _eo_neon vcombine_u8(vdupq_n_u8(0x10), vdupq_n_u8(0x10))
13
14// static cube
15#define static_cube(c_ufr, c_ubl, c_dfl, c_dbr, c_ufl, c_ubr, c_dfr, c_dbl, \
16 e_uf, e_ub, e_db, e_df, e_ur, e_ul, e_dl, e_dr, e_fr, e_fl, e_bl, e_br) \
17 ((cube_t){ \
18 .corner = {c_ufr, c_ubl, c_dfl, c_dbr, c_ufl, c_ubr, c_dfr, c_dbl, 0, 0, 0, 0, 0, 0, 0, 0}, \
19 .edge = {e_uf, e_ub, e_db, e_df, e_ur, e_ul, e_dl, e_dr, e_fr, e_fl, e_bl, e_br, 0, 0, 0, 0}})
20
21// zero cube
22#define zero \
23 (cube_t) \
24 { \
25 .corner = vdupq_n_u8(0), \
26 .edge = vdupq_n_u8(0) \
27 }
28
29// solved cube
30#define solved static_cube( \
31 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
32
33// Functions
34_static void pieces(cube_t *, uint8_t[static 8], uint8_t[static 12]);
35_static_inline bool equal(cube_t, cube_t);
36_static_inline cube_t invertco(cube_t);
37_static_inline cube_t compose_edges(cube_t, cube_t);
38_static_inline cube_t compose_corners(cube_t, cube_t);
39_static_inline uint8x16_t compose_edges_slim(uint8x16_t, uint8x16_t);
40_static_inline uint8x16_t compose_corners_slim(uint8x16_t, uint8x16_t);
41_static_inline cube_t compose(cube_t, cube_t);
42_static_inline cube_t inverse(cube_t);
43
44_static_inline int64_t coord_co(cube_t);
45_static_inline int64_t coord_csep(cube_t);
46_static_inline int64_t coord_cocsep(cube_t);
47_static_inline int64_t coord_eo(cube_t);
48_static_inline int64_t coord_esep(cube_t);
49
50_static_inline void copy_corners(cube_t *, cube_t);
51_static_inline void copy_edges(cube_t *, cube_t);
52_static_inline void set_eo(cube_t *, int64_t);
53_static_inline cube_t invcoord_esep(int64_t);
54
55_static void
56pieces(cube_t *cube, uint8_t c[static 8], uint8_t e[static 12])
57{
58 // First 8 bytes of the corner vector are copied from the c array
59 vst1_u8(c, vget_low_u8(cube->corner));
60
61 // 12 bytes of the edge vector are copied from the e array
62 // First 8 bytes
63 vst1_u8(e, vget_low_u8(cube->edge));
64 // Next 4 bytes
65 vst1_lane_u32((uint32_t *)(e + 8), vreinterpret_u32_u8(vget_high_u8(cube->edge)), 0);
66}
67
68_static_inline bool
69equal(cube_t c1, cube_t c2)
70{
71 uint8x16_t cmp_corner, cmp_edge;
72 uint64x2_t cmp_corner_u64, cmp_edge_u64;
73 uint64x2_t cmp_result;
74
75 // compare the corner vectors
76 cmp_corner = vceqq_u8(c1.corner, c2.corner);
77 // compare the edge vectors
78 cmp_edge = vceqq_u8(c1.edge, c2.edge);
79
80 // convert the comparison vectors to 64-bit vectors
81 cmp_corner_u64 = vreinterpretq_u64_u8(cmp_corner);
82 cmp_edge_u64 = vreinterpretq_u64_u8(cmp_edge);
83
84 // combine the comparison vectors
85 cmp_result = vandq_u64(cmp_corner_u64, cmp_edge_u64);
86
87 // check if all the bits are set
88 return vgetq_lane_u64(cmp_result, 0) == ~0ULL && vgetq_lane_u64(cmp_result, 1) == ~0ULL;
89}
90
91_static_inline cube_t
92invertco(cube_t c)
93{
94 cube_t ret;
95 uint8x16_t co, shleft, shright, summed, newco, cleanco;
96
97 co = vandq_u8(c.corner, _co2_neon);
98 shleft = vshlq_n_u8(co, 1);
99 shright = vshrq_n_u8(co, 1);
100 summed = vorrq_u8(shleft, shright);
101 newco = vandq_u8(summed, _co2_neon);
102 cleanco = veorq_u8(c.corner, co);
103 ret.corner = vorrq_u8(cleanco, newco);
104 ret.edge = c.edge;
105
106 return ret;
107}
108
109_static_inline cube_t
110compose_edges(cube_t c1, cube_t c2)
111{
112 cube_t ret = {0};
113 ret.edge = compose_edges_slim(c1.edge, c2.edge);
114 return ret;
115}
116
117_static_inline cube_t
118compose_corners(cube_t c1, cube_t c2)
119{
120 cube_t ret = {0};
121 ret.corner = compose_corners_slim(c1.corner, c2.corner);
122 return ret;
123}
124
125_static_inline uint8x16_t
126compose_edges_slim(uint8x16_t edge1, uint8x16_t edge2)
127{
128 // Masks
129 uint8x16_t p_bits = vdupq_n_u8(_pbits);
130 uint8x16_t eo_bit = vdupq_n_u8(_eobit);
131
132 // Find the index and permutation
133 uint8x16_t p = vandq_u8(edge2, p_bits);
134 uint8x16_t piece1 = vqtbl1q_u8(edge1, p);
135
136 // Calculate the orientation through XOR
137 uint8x16_t orien = vandq_u8(veorq_u8(edge2, piece1), eo_bit);
138
139 // Combine the results
140 uint8x16_t ret = vorrq_u8(vandq_u8(piece1, p_bits), orien);
141
142 // Mask to clear the last 32 bits of the result
143 uint8x16_t mask_last_32 = vsetq_lane_u32(0, vreinterpretq_u32_u8(ret), 3);
144 ret = vreinterpretq_u8_u32(mask_last_32);
145
146 return ret;
147}
148
149_static_inline uint8x16_t
150compose_corners_slim(uint8x16_t corner1, uint8x16_t corner2)
151{
152 // Masks
153 uint8x16_t p_bits = vdupq_n_u8(_pbits);
154 uint8x16_t cobits = vdupq_n_u8(_cobits);
155 uint8x16_t cobits2 = vdupq_n_u8(_cobits2);
156 uint8x16_t twist_cw = vdupq_n_u8(_ctwist_cw);
157
158 // Find the index and permutation
159 uint8x16_t p = vandq_u8(corner2, p_bits);
160 uint8x16_t piece1 = vqtbl1q_u8(corner1, p);
161
162 // Calculate the orientation
163 uint8x16_t aux = vaddq_u8(vandq_u8(corner2, cobits), vandq_u8(piece1, cobits));
164 uint8x16_t auy = vshrq_n_u8(vaddq_u8(aux, twist_cw), 2);
165 uint8x16_t orien = vandq_u8(vaddq_u8(aux, auy), cobits2);
166
167 // Combine the results
168 uint8x16_t ret = vorrq_u8(vandq_u8(piece1, p_bits), orien);
169
170 // Mask to clear the last 64 bits of the result
171 uint8x16_t mask_last_64 = vsetq_lane_u64(0, vreinterpretq_u64_u8(ret), 1);
172 ret = vreinterpretq_u8_u64(mask_last_64);
173
174 return ret;
175}
176
177_static_inline cube_t
178compose(cube_t c1, cube_t c2)
179{
180 cube_t ret = {0};
181
182 ret.edge = compose_edges_slim(c1.edge, c2.edge);
183 ret.corner = compose_corners_slim(c1.corner, c2.corner);
184
185 return ret;
186}
187
188_static_inline cube_t
189inverse(cube_t cube)
190{
191 uint8_t i, piece, orien;
192 cube_t ret;
193
194 // Temp arrays to store the NEON vectors
195 uint8_t edges[16];
196 uint8_t corners[16];
197
198 // Copy the NEON vectors to the arrays
199 vst1q_u8(edges, cube.edge);
200 vst1q_u8(corners, cube.corner);
201
202 uint8_t edge_result[16] = {0};
203 uint8_t corner_result[16] = {0};
204
205 // Process the edges
206 for (i = 0; i < 12; i++)
207 {
208 piece = edges[i];
209 orien = piece & _eobit;
210 edge_result[piece & _pbits] = i | orien;
211 }
212
213 // Process the corners
214 for (i = 0; i < 8; i++)
215 {
216 piece = corners[i];
217 orien = ((piece << 1) | (piece >> 1)) & _cobits2;
218 corner_result[piece & _pbits] = i | orien;
219 }
220
221 // Copy the results back to the NEON vectors
222 ret.edge = vld1q_u8(edge_result);
223 ret.corner = vld1q_u8(corner_result);
224
225 return ret;
226}
227
228_static_inline int64_t
229coord_co(cube_t c)
230{
231 // Temp array to store the NEON vector
232 uint8_t mem[16];
233 vst1q_u8(mem, c.corner);
234
235 int i, p;
236 int64_t ret;
237
238 for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 3)
239 ret += p * (mem[i] >> _coshift);
240
241 return ret;
242}
243
244_static_inline int64_t
245coord_csep(cube_t c)
246{
247 // Temp array to store the NEON vector
248 uint8_t mem[16];
249 vst1q_u8(mem, c.corner);
250
251 int64_t ret = 0;
252 int i, p;
253 for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 2)
254 ret += p * ((mem[i] & _csepbit) >> 2);
255
256 return ret;
257 return 0;
258}
259
260_static_inline int64_t
261coord_cocsep(cube_t c)
262{
263 return (coord_co(c) << 7) + coord_csep(c);
264}
265
266_static_inline int64_t
267coord_eo(cube_t c)
268{
269 int64_t ret = 0;
270 int64_t p = 1;
271
272 // Temp array to store the NEON vector
273 uint8_t mem[16];
274 vst1q_u8(mem, c.edge);
275
276 for (int i = 1; i < 12; i++, p *= 2)
277 {
278 ret += p * (mem[i] >> _eoshift);
279 }
280
281 return ret;
282}
283
284_static_inline int64_t
285coord_esep(cube_t c)
286{
287 int64_t i, j, jj, k, l, ret1, ret2, bit1, bit2, is1;
288
289 // Temp array to store the NEON vector
290 uint8_t mem[16];
291 vst1q_u8(mem, c.edge);
292
293 for (i = 0, j = 0, k = 4, l = 4, ret1 = 0, ret2 = 0; i < 12; i++)
294 {
295 bit1 = (mem[i] & _esepbit1) >> 2;
296 bit2 = (mem[i] & _esepbit2) >> 3;
297 is1 = (1 - bit2) * bit1;
298
299 ret1 += bit2 * binomial[11 - i][k];
300 k -= bit2;
301
302 jj = j < 8;
303 ret2 += jj * is1 * binomial[7 - (j * jj)][l];
304 l -= is1;
305 j += (1 - bit2);
306 }
307
308 return ret1 * 70 + ret2;
309}
310
311_static_inline void
312copy_corners(cube_t *dst, cube_t src)
313{
314 dst->corner = src.corner;
315}
316
317_static_inline void
318copy_edges(cube_t *dst, cube_t src)
319{
320 dst->edge = src.edge;
321}
322
323_static_inline void
324set_eo(cube_t *cube, int64_t eo)
325{
326 // Temp array to store the NEON vector
327 uint8_t mem[16];
328 vst1q_u8(mem, cube->edge);
329 uint8_t i, sum, flip;
330
331 for (sum = 0, i = 1; i < 12; i++, eo >>= 1)
332 {
333 flip = eo % 2;
334 sum += flip;
335 mem[i] = (mem[i] & ~_eobit) | (_eobit * flip);
336 }
337 mem[0] = (mem[0] & ~_eobit) | (_eobit * (sum % 2));
338
339 // Copy the results back to the NEON vector
340 cube->edge = vld1q_u8(mem);
341 return;
342}
343
344_static_inline cube_t
345invcoord_esep(int64_t esep)
346{
347 cube_t ret;
348 int64_t bit1, bit2, i, j, jj, k, l, s, v, w, is1, set1, set2;
349 uint8_t slice[3] = {0};
350
351 ret = solved;
352 uint8_t mem[16];
353 set1 = esep % 70;
354 set2 = esep / 70;
355
356 for (i = 0, j = 0, k = 4, l = 4; i < 12; i++)
357 {
358 v = binomial[11 - i][k];
359 jj = j < 8;
360 w = jj * binomial[7 - (j * jj)][l];
361 bit2 = set2 >= v;
362 bit1 = set1 >= w;
363 is1 = (1 - bit2) * bit1;
364
365 set2 -= bit2 * v;
366 k -= bit2;
367 set1 -= is1 * w;
368 l -= is1;
369 j += (1 - bit2);
370 s = 2 * bit2 + (1 - bit2) * bit1;
371
372 mem[i] = (slice[s]++) | (uint8_t)(s << 2);
373 }
374
375 ret.edge = vld1q_u8(mem);
376 return ret;
377}

Generated with cgit - Back to sebastiano.tronto.net