aboutsummaryrefslogtreecommitdiff
path: root/src/cube_neon.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/cube_neon.h')
-rw-r--r--src/cube_neon.h440
1 files changed, 435 insertions, 5 deletions
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}

Generated with cgit - Back to sebastiano.tronto.net