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

Generated with cgit - Back to sebastiano.tronto.net