aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorenricotenuti <tenutz_27@outlook.it>2024-08-07 20:09:12 +0200
committerenricotenuti <tenutz_27@outlook.it>2024-08-07 20:09:12 +0200
commitd613e7258bca459a59cdb7b4fb8a7cb041137377 (patch)
tree28b3341cf75e2348a26ab9ee44f386c9cda22cfd
parentf148aa65dfe587e7b5d2f48b5005be670788dbe6 (diff)
downloadnissy-core-d613e7258bca459a59cdb7b4fb8a7cb041137377.tar.gz
nissy-core-d613e7258bca459a59cdb7b4fb8a7cb041137377.zip
cube_neon ver1
-rw-r--r--.gitignore2
-rw-r--r--src/cube.c2
-rw-r--r--src/cube_neon.h440
-rw-r--r--test/104_cocsep_ttrep/cocsep_ttrep_tests.c2
-rw-r--r--test/test.h9
-rwxr-xr-xtest/test.sh33
6 files changed, 466 insertions, 22 deletions
diff --git a/.gitignore b/.gitignore
index b942bed..5fb5b1f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,7 +7,9 @@ run
7tables/* 7tables/*
8test/*/runtest 8test/*/runtest
9test/run 9test/run
10test/run.DSYM
10test/last.* 11test/last.*
11tools/results 12tools/results
13.vscode
12*.o 14*.o
13*.s 15*.s
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..4739593 100644
--- a/src/cube_neon.h
+++ b/src/cube_neon.h
@@ -1,6 +1,436 @@
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// static cube
9#define static_cube(c_ufr, c_ubl, c_dfl, c_dbr, c_ufl, c_ubr, c_dfr, c_dbl, \
10 e_uf, e_ub, e_db, e_df, e_ur, e_ul, e_dl, e_dr, e_fr, e_fl, e_bl, e_br) \
11 ((cube_t){ \
12 .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}, \
13 .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}})
14
15// zero cube
16#define zero \
17 (cube_t) \
18 { \
19 .corner = vdupq_n_u8(0), \
20 .edge = vdupq_n_u8(0) \
21 }
22
23// solved cube
24#define solved static_cube( \
25 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
26
27// Functions
28_static void pieces(cube_t *, uint8_t[static 8], uint8_t[static 12]);
29_static_inline bool equal(cube_t, cube_t);
30_static_inline cube_t invertco(cube_t);
31_static_inline cube_t compose_edges(cube_t, cube_t); // implementation similar to portable compose_edges_inplace
32_static_inline cube_t compose_corners(cube_t, cube_t); // implementation similar to portable compose_corners_inplace
33_static_inline uint8x16_t compose_edges_slim(uint8x16_t, uint8x16_t); // similar to compose_edges but without the cube_t struct
34_static_inline uint8x16_t compose_corners_slim(uint8x16_t, uint8x16_t); // similar to compose_corners but without the cube_t struct
35_static_inline cube_t compose(cube_t, cube_t);
36_static_inline cube_t inverse(cube_t);
37
38_static_inline int64_t coord_co(cube_t);
39_static_inline int64_t coord_csep(cube_t);
40_static_inline int64_t coord_cocsep(cube_t);
41_static_inline int64_t coord_eo(cube_t);
42_static_inline int64_t coord_esep(cube_t);
43
44_static_inline void copy_corners(cube_t *, cube_t);
45_static_inline void copy_edges(cube_t *, cube_t);
46_static_inline void set_eo(cube_t *, int64_t);
47_static_inline cube_t invcoord_esep(int64_t);
48/*
49_static void pieces(cube_t *cube, uint8_t c[static 8], uint8_t e[static 12]) {
50 uint8_t aux[32];
51
52 // Store the corner and edge vectors into the aux array
53 vst1q_u8(aux, cube->corner);
54 vst1q_u8(aux + 16, cube->edge);
55
56 // Copy the required parts to the output arrays
57 memcpy(c, aux, 8);
58 memcpy(e, aux + 16, 12);
59}
60*/
61
62_static void
63pieces(cube_t *cube, uint8_t c[static 8], uint8_t e[static 12])
64{
65 // First 8 bytes of the corner vector are copied from the c array
66 vst1_u8(c, vget_low_u8(cube->corner));
67
68 // 12 bytes of the edge vector are copied from the e array
69 // First 8 bytes
70 vst1_u8(e, vget_low_u8(cube->edge));
71 // Next 4 bytes
72 vst1_lane_u32((uint32_t *)(e + 8), vreinterpret_u32_u8(vget_high_u8(cube->edge)), 0);
73}
74
75_static_inline bool
76equal(cube_t c1, cube_t c2)
77{
78 uint8x16_t cmp_corner, cmp_edge;
79 uint64x2_t cmp_corner_u64, cmp_edge_u64;
80 uint64x2_t cmp_result;
81
82 // compare the corner vectors
83 cmp_corner = vceqq_u8(c1.corner, c2.corner);
84 // compare the edge vectors
85 cmp_edge = vceqq_u8(c1.edge, c2.edge);
86
87 // convert the comparison vectors to 64-bit vectors
88 cmp_corner_u64 = vreinterpretq_u64_u8(cmp_corner);
89 cmp_edge_u64 = vreinterpretq_u64_u8(cmp_edge);
90
91 // combine the comparison vectors
92 cmp_result = vandq_u64(cmp_corner_u64, cmp_edge_u64);
93
94 // check if all the bits are set
95 return vgetq_lane_u64(cmp_result, 0) == ~0ULL && vgetq_lane_u64(cmp_result, 1) == ~0ULL;
96}
97
98_static_inline cube_t invertco(cube_t c)
99{
100 cube_t ret;
101
102 // Copy the corner vector to an array
103 uint8_t corners[16];
104 vst1q_u8(corners, c.corner);
105
106 uint8_t corner_result[16] = {0};
107
108 // Process the corners
109 for (uint8_t i = 0; i < 8; i++)
110 {
111 uint8_t piece = corners[i];
112 uint8_t orien = ((piece << 1) | (piece >> 1)) & _cobits2;
113 corner_result[i] = (piece & _pbits) | orien;
114 }
115
116 // Copy the results back to the NEON corner vector
117 ret.corner = vld1q_u8(corner_result);
118
119 // Mask to clear the last 64 bits of the corner field
120 uint8x16_t mask_last_64 = vsetq_lane_u64(0, vreinterpretq_u64_u8(ret.corner), 1);
121 ret.corner = vreinterpretq_u8_u64(mask_last_64);
122
123 // Copy the edge vector as it is
124 ret.edge = c.edge;
125
126 // Mask to clear the last 32 bits of the edge field
127 uint8x16_t mask_last_32 = vsetq_lane_u32(0, vreinterpretq_u32_u8(ret.edge), 3);
128 ret.edge = vreinterpretq_u8_u32(mask_last_32);
129
130 return ret;
131}
132
133_static_inline cube_t compose_edges(cube_t c1, cube_t c2)
134{
135 cube_t ret = {0};
136
137 uint8x16_t edge1 = c1.edge;
138 uint8x16_t edge2 = c2.edge;
139
140 // Masks
141 uint8x16_t p_bits = vdupq_n_u8(_pbits);
142 uint8x16_t eo_bit = vdupq_n_u8(_eobit);
143
144 // Find the index and permutation
145 uint8x16_t p = vandq_u8(edge2, p_bits);
146 uint8x16_t piece1 = vqtbl1q_u8(edge1, p);
147
148 // Calculate the orientation through XOR
149 uint8x16_t orien = vandq_u8(veorq_u8(edge2, piece1), eo_bit);
150
151 // Combine the results
152 uint8x16_t result = vorrq_u8(vandq_u8(piece1, p_bits), orien);
153
154 // Mask to clear the last 32 bits of the result
155 uint8x16_t mask_last_32 = vsetq_lane_u32(0, vreinterpretq_u32_u8(result), 3);
156 result = vreinterpretq_u8_u32(mask_last_32);
157
158 ret.edge = result;
159 return ret;
160}
161
162_static_inline cube_t compose_corners(cube_t c1, cube_t c2)
163{
164 cube_t ret = {0};
165 uint8x16_t corner1 = c1.corner;
166 uint8x16_t corner2 = c2.corner;
167
168 // Masks
169 uint8x16_t p_bits = vdupq_n_u8(_pbits);
170 uint8x16_t cobits = vdupq_n_u8(_cobits);
171 uint8x16_t cobits2 = vdupq_n_u8(_cobits2);
172 uint8x16_t twist_cw = vdupq_n_u8(_ctwist_cw);
173
174 // Find the index and permutation
175 uint8x16_t p = vandq_u8(corner2, p_bits);
176 uint8x16_t piece1 = vqtbl1q_u8(corner1, p);
177
178 // Calculate the orientation
179 uint8x16_t aux = vaddq_u8(vandq_u8(corner2, cobits), vandq_u8(piece1, cobits));
180 uint8x16_t auy = vshrq_n_u8(vaddq_u8(aux, twist_cw), 2);
181 uint8x16_t orien = vandq_u8(vaddq_u8(aux, auy), cobits2);
182
183 // Combine the results
184 uint8x16_t result = vorrq_u8(vandq_u8(piece1, p_bits), orien);
185
186 // Mask to clear the last 64 bits of the result
187 uint8x16_t mask_last_64 = vsetq_lane_u64(0, vreinterpretq_u64_u8(result), 1);
188 result = vreinterpretq_u8_u64(mask_last_64);
189
190 ret.corner = result;
191 return ret;
192}
193_static_inline uint8x16_t compose_edges_slim(uint8x16_t edge1, uint8x16_t edge2)
194{
195 // Masks
196 uint8x16_t p_bits = vdupq_n_u8(_pbits);
197 uint8x16_t eo_bit = vdupq_n_u8(_eobit);
198
199 // Find the index and permutation
200 uint8x16_t p = vandq_u8(edge2, p_bits);
201 uint8x16_t piece1 = vqtbl1q_u8(edge1, p);
202
203 // Calculate the orientation through XOR
204 uint8x16_t orien = vandq_u8(veorq_u8(edge2, piece1), eo_bit);
205
206 // Combine the results
207 uint8x16_t ret = vorrq_u8(vandq_u8(piece1, p_bits), orien);
208
209 // Mask to clear the last 32 bits of the result
210 uint8x16_t mask_last_32 = vsetq_lane_u32(0, vreinterpretq_u32_u8(ret), 3);
211 ret = vreinterpretq_u8_u32(mask_last_32);
212
213 return ret;
214}
215_static_inline uint8x16_t compose_corners_slim(uint8x16_t corner1, uint8x16_t corner2)
216{
217 // Masks
218 uint8x16_t p_bits = vdupq_n_u8(_pbits);
219 uint8x16_t cobits = vdupq_n_u8(_cobits);
220 uint8x16_t cobits2 = vdupq_n_u8(_cobits2);
221 uint8x16_t twist_cw = vdupq_n_u8(_ctwist_cw);
222
223 // Find the index and permutation
224 uint8x16_t p = vandq_u8(corner2, p_bits);
225 uint8x16_t piece1 = vqtbl1q_u8(corner1, p);
226
227 // Calculate the orientation
228 uint8x16_t aux = vaddq_u8(vandq_u8(corner2, cobits), vandq_u8(piece1, cobits));
229 uint8x16_t auy = vshrq_n_u8(vaddq_u8(aux, twist_cw), 2);
230 uint8x16_t orien = vandq_u8(vaddq_u8(aux, auy), cobits2);
231
232 // Combine the results
233 uint8x16_t ret = vorrq_u8(vandq_u8(piece1, p_bits), orien);
234
235 // Mask to clear the last 64 bits of the result
236 uint8x16_t mask_last_64 = vsetq_lane_u64(0, vreinterpretq_u64_u8(ret), 1);
237 ret = vreinterpretq_u8_u64(mask_last_64);
238
239 return ret;
240}
241_static_inline cube_t compose(cube_t c1, cube_t c2)
242{
243 cube_t ret = {0};
244
245 ret.edge = compose_edges_slim(c1.edge, c2.edge);
246 ret.corner = compose_corners_slim(c1.corner, c2.corner);
247
248 return ret;
249}
250
251_static_inline cube_t inverse(cube_t cube)
252{
253 uint8_t i, piece, orien;
254 cube_t ret;
255
256 // Temp arrays to store the NEON vectors
257 uint8_t edges[16];
258 uint8_t corners[16];
259
260 // Copy the NEON vectors to the arrays
261 vst1q_u8(edges, cube.edge);
262 vst1q_u8(corners, cube.corner);
263
264 uint8_t edge_result[16] = {0};
265 uint8_t corner_result[16] = {0};
266
267 // Process the edges
268 for (i = 0; i < 12; i++)
269 {
270 piece = edges[i];
271 orien = piece & _eobit;
272 edge_result[piece & _pbits] = i | orien;
273 }
274
275 // Process the corners
276 for (i = 0; i < 8; i++)
277 {
278 piece = corners[i];
279 orien = ((piece << 1) | (piece >> 1)) & _cobits2;
280 corner_result[piece & _pbits] = i | orien;
281 }
282
283 // Copy the results back to the NEON vectors
284 ret.edge = vld1q_u8(edge_result);
285 ret.corner = vld1q_u8(corner_result);
286
287 return ret;
288}
289
290_static_inline int64_t coord_co(cube_t c)
291{
292 // Temp array to store the NEON vector
293 uint8_t mem[16];
294 vst1q_u8(mem, c.corner);
295
296 int i, p;
297 int64_t ret;
298
299 for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 3)
300 ret += p * (mem[i] >> _coshift);
301
302 return ret;
303}
304
305_static_inline int64_t
306coord_csep(cube_t c)
307{
308 // Temp array to store the NEON vector
309 uint8_t mem[16];
310 vst1q_u8(mem, c.corner);
311
312 int64_t ret = 0;
313 int i, p;
314 for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 2)
315 ret += p * ((mem[i] & _csepbit) >> 2);
316
317 return ret;
318 return 0;
319}
320
321_static_inline int64_t
322coord_cocsep(cube_t c)
323{
324 return (coord_co(c) << 7) + coord_csep(c);
325}
326
327_static_inline int64_t coord_eo(cube_t c)
328{
329 int64_t ret = 0;
330 int64_t p = 1;
331
332 // Temp array to store the NEON vector
333 uint8_t mem[16];
334 vst1q_u8(mem, c.edge);
335
336 for (int i = 1; i < 12; i++, p *= 2)
337 {
338 ret += p * (mem[i] >> _eoshift);
339 }
340
341 return ret;
342}
343
344_static_inline int64_t coord_esep(cube_t c)
345{
346 int64_t i, j, jj, k, l, ret1, ret2, bit1, bit2, is1;
347
348 // Temp array to store the NEON vector
349 uint8_t mem[16];
350 vst1q_u8(mem, c.edge);
351
352 for (i = 0, j = 0, k = 4, l = 4, ret1 = 0, ret2 = 0; i < 12; i++)
353 {
354 bit1 = (mem[i] & _esepbit1) >> 2;
355 bit2 = (mem[i] & _esepbit2) >> 3;
356 is1 = (1 - bit2) * bit1;
357
358 ret1 += bit2 * binomial[11 - i][k];
359 k -= bit2;
360
361 jj = j < 8;
362 ret2 += jj * is1 * binomial[7 - (j * jj)][l];
363 l -= is1;
364 j += (1 - bit2);
365 }
366
367 return ret1 * 70 + ret2;
368}
369
370_static_inline void
371copy_corners(cube_t *dst, cube_t src)
372{
373 dst->corner = src.corner;
374}
375
376_static_inline void
377copy_edges(cube_t *dst, cube_t src)
378{
379 dst->edge = src.edge;
380}
381
382_static_inline void
383set_eo(cube_t *cube, int64_t eo)
384{
385 // Temp array to store the NEON vector
386 uint8_t mem[16];
387 vst1q_u8(mem, cube->edge);
388 uint8_t i, sum, flip;
389
390 for (sum = 0, i = 1; i < 12; i++, eo >>= 1)
391 {
392 flip = eo % 2;
393 sum += flip;
394 mem[i] = (mem[i] & ~_eobit) | (_eobit * flip);
395 }
396 mem[0] = (mem[0] & ~_eobit) | (_eobit * (sum % 2));
397
398 // Copy the results back to the NEON vector
399 cube->edge = vld1q_u8(mem);
400 return;
401}
402
403_static_inline cube_t
404invcoord_esep(int64_t esep)
405{
406 cube_t ret;
407 int64_t bit1, bit2, i, j, jj, k, l, s, v, w, is1, set1, set2;
408 uint8_t slice[3] = {0};
409
410 ret = solved;
411 uint8_t mem[16];
412 set1 = esep % 70;
413 set2 = esep / 70;
414
415 for (i = 0, j = 0, k = 4, l = 4; i < 12; i++)
416 {
417 v = binomial[11 - i][k];
418 jj = j < 8;
419 w = jj * binomial[7 - (j * jj)][l];
420 bit2 = set2 >= v;
421 bit1 = set1 >= w;
422 is1 = (1 - bit2) * bit1;
423
424 set2 -= bit2 * v;
425 k -= bit2;
426 set1 -= is1 * w;
427 l -= is1;
428 j += (1 - bit2);
429 s = 2 * bit2 + (1 - bit2) * bit1;
430
431 mem[i] = (slice[s]++) | (uint8_t)(s << 2);
432 }
433
434 ret.edge = vld1q_u8(mem);
435 return ret;
436}
diff --git a/test/104_cocsep_ttrep/cocsep_ttrep_tests.c b/test/104_cocsep_ttrep/cocsep_ttrep_tests.c
index f0da151..f692ca8 100644
--- a/test/104_cocsep_ttrep/cocsep_ttrep_tests.c
+++ b/test/104_cocsep_ttrep/cocsep_ttrep_tests.c
@@ -29,7 +29,7 @@ void run(void) {
29 l = coord_cocsep(c); 29 l = coord_cocsep(c);
30 if (k != l) 30 if (k != l)
31 printf("cocsep %" PRId64 " (%" PRId64 "): " 31 printf("cocsep %" PRId64 " (%" PRId64 "): "
32 "%" PRId64 " ttrep %" PRIu8 32 "%" PRId64 " ttrep %" PRIu32
33 " -> %" PRId64 "\n", i, l, j, tt, k); 33 " -> %" PRId64 "\n", i, l, j, tt, k);
34 } 34 }
35 } 35 }
diff --git a/test/test.h b/test/test.h
index d092244..1f4b2c3 100644
--- a/test/test.h
+++ b/test/test.h
@@ -7,9 +7,16 @@
7 7
8#define STRLENMAX 10000 8#define STRLENMAX 10000
9 9
10#ifdef CUBE_AVX2 10#if defined(CUBE_AVX2)
11#include <immintrin.h> 11#include <immintrin.h>
12typedef __m256i cube_t; 12typedef __m256i cube_t;
13#elif defined(CUBE_NEON)
14#include <stdlib.h>
15#include <arm_neon.h>
16typedef struct {
17 uint8x16_t corner;
18 uint8x16_t edge;
19} cube_t;
13#else 20#else
14typedef struct { 21typedef struct {
15 uint8_t corner[8]; 22 uint8_t corner[8];
diff --git a/test/test.sh b/test/test.sh
index 33613b1..4325c91 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -11,21 +11,24 @@ for t in test/*; do
11 if [ -n "$re" ] && [ -z "$(echo "$t" | grep "$re")" ]; then 11 if [ -n "$re" ] && [ -z "$(echo "$t" | grep "$re")" ]; then
12 continue 12 continue
13 fi 13 fi
14 if [ ! -d $t ]; then continue; fi 14
15 $CC -o $TESTBIN $t/*.c $CUBEOBJ || exit 1; 15 # Verifica se $t รจ una directory e se il suo nome inizia con tre cifre
16 for cin in $t/*.in; do 16 if [ -d "$t" ] && echo "$(basename "$t")" | grep -Eq '^[0-9]{3}'; then
17 c=$(echo "$cin" | sed 's/\.in//') 17 $CC -o $TESTBIN $t/*.c $CUBEOBJ || exit 1
18 cout=$c.out 18 for cin in $t/*.in; do
19 printf "$c: " 19 c=$(echo "$cin" | sed 's/\.in//')
20 $TESTBIN < "$cin" > $TESTOUT 2> $TESTERR 20 cout=$c.out
21 if diff $cout $TESTOUT; then 21 printf "$c: "
22 printf "OK\n" 22 $TESTBIN < "$cin" > $TESTOUT 2> $TESTERR
23 else 23 if diff $cout $TESTOUT; then
24 printf "Test failed! stderr:\n" 24 printf "OK\n"
25 cat $TESTERR 25 else
26 exit 1 26 printf "Test failed! stderr:\n"
27 fi 27 cat $TESTERR
28 done 28 exit 1
29 fi
30 done
31 fi
29done 32done
30 33
31echo "All tests passed!" 34echo "All tests passed!"

Generated with cgit - Back to sebastiano.tronto.net