aboutsummaryrefslogtreecommitdiff
path: root/src/cube.c
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2023-10-28 20:42:24 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2023-10-28 20:42:24 +0200
commitb05fa355c49c619cce1226716a395381a944f578 (patch)
treeb46416e2fbbc70f3d780f4e0ea3de7763115efe0 /src/cube.c
parentfabb1ae495c4404af0f26380c97d0bca7e881a27 (diff)
downloadnissy-core-b05fa355c49c619cce1226716a395381a944f578.tar.gz
nissy-core-b05fa355c49c619cce1226716a395381a944f578.zip
Started working on AVX2 (not working yet)
Diffstat (limited to '')
-rw-r--r--src/cube.c296
1 files changed, 100 insertions, 196 deletions
diff --git a/src/cube.c b/src/cube.c
index 1e27de9..4651b00 100644
--- a/src/cube.c
+++ b/src/cube.c
@@ -2,6 +2,10 @@
2#include <stdbool.h> 2#include <stdbool.h>
3#include <string.h> 3#include <string.h>
4 4
5#ifdef CUBE_AVX2
6#include <immintrin.h>
7#endif
8
5#ifdef DEBUG 9#ifdef DEBUG
6#include <stdio.h> 10#include <stdio.h>
7#endif 11#endif
@@ -10,6 +14,12 @@
10 14
11#include "_constants.c" 15#include "_constants.c"
12 16
17#ifdef CUBE_AVX2
18#include "_base_avx2.c"
19#else
20#include "_base_arr.c"
21#endif
22
13static bool isconsistent(cube_t); 23static bool isconsistent(cube_t);
14static cube_t flipallcorners(cube_t); 24static cube_t flipallcorners(cube_t);
15static uint8_t readco(char *); 25static uint8_t readco(char *);
@@ -90,7 +100,7 @@ readcube_H48(char *buf)
90{ 100{
91 int i; 101 int i;
92 uint8_t piece, orient; 102 uint8_t piece, orient;
93 cube_t ret = {0}; 103 cube_t ret = zerocube;
94 char *b = buf; 104 char *b = buf;
95 105
96 for (i = 0; i < 12; i++) { 106 for (i = 0; i < 12; i++) {
@@ -102,7 +112,7 @@ readcube_H48(char *buf)
102 if ((orient = readeo(b)) == _error) 112 if ((orient = readeo(b)) == _error)
103 return errorcube; 113 return errorcube;
104 b++; 114 b++;
105 ret.e[i] = piece | orient; 115 set_edge(&ret, i, piece | orient);
106 } 116 }
107 for (i = 0; i < 8; i++) { 117 for (i = 0; i < 8; i++) {
108 while (*b == ' ' || *b == '\t' || *b == '\n') 118 while (*b == ' ' || *b == '\t' || *b == '\n')
@@ -113,7 +123,7 @@ readcube_H48(char *buf)
113 if ((orient = readco(b)) == _error) 123 if ((orient = readco(b)) == _error)
114 return errorcube; 124 return errorcube;
115 b++; 125 b++;
116 ret.c[i] = piece | orient; 126 set_corner(&ret, i, piece | orient);
117 } 127 }
118 128
119 return ret; 129 return ret;
@@ -145,23 +155,25 @@ readcube(format_t format, char *buf)
145static void 155static void
146writecube_H48(cube_t cube, char *buf) 156writecube_H48(cube_t cube, char *buf)
147{ 157{
148 uint8_t piece, orient; 158 uint8_t piece, perm, orient;
149 int i; 159 int i;
150 160
151 for (i = 0; i < 12; i++) { 161 for (i = 0; i < 12; i++) {
152 piece = cube.e[i] & _pbits; 162 piece = get_edge(cube, i);
153 orient = (cube.e[i] & _eobit) >> _eoshift; 163 perm = piece & _pbits;
154 buf[4*i ] = edgestr[piece][0]; 164 orient = (piece & _eobit) >> _eoshift;
155 buf[4*i + 1] = edgestr[piece][1]; 165 buf[4*i ] = edgestr[perm][0];
166 buf[4*i + 1] = edgestr[perm][1];
156 buf[4*i + 2] = orient + '0'; 167 buf[4*i + 2] = orient + '0';
157 buf[4*i + 3] = ' '; 168 buf[4*i + 3] = ' ';
158 } 169 }
159 for (i = 0; i < 8; i++) { 170 for (i = 0; i < 8; i++) {
160 piece = cube.c[i] & _pbits; 171 piece = get_corner(cube, i);
161 orient = (cube.c[i] & _cobits) >> _coshift; 172 perm = piece & _pbits;
162 buf[48 + 5*i ] = cornerstr[piece][0]; 173 orient = (piece & _cobits) >> _coshift;
163 buf[48 + 5*i + 1] = cornerstr[piece][1]; 174 buf[48 + 5*i ] = cornerstr[perm][0];
164 buf[48 + 5*i + 2] = cornerstr[piece][2]; 175 buf[48 + 5*i + 1] = cornerstr[perm][1];
176 buf[48 + 5*i + 2] = cornerstr[perm][2];
165 buf[48 + 5*i + 3] = orient + '0'; 177 buf[48 + 5*i + 3] = orient + '0';
166 buf[48 + 5*i + 4] = ' '; 178 buf[48 + 5*i + 4] = ' ';
167 } 179 }
@@ -196,18 +208,23 @@ static void
196writecube_SRC(cube_t cube, char *buf) 208writecube_SRC(cube_t cube, char *buf)
197{ 209{
198 int i, ptr; 210 int i, ptr;
211 uint8_t piece;
199 212
200 memcpy(buf, "{\n\t.c = {", 9); 213 memcpy(buf, "{\n\t.c = {", 9);
201 ptr = 9; 214 ptr = 9;
202 215
203 for (i = 0; i < 8; i++) 216 for (i = 0; i < 8; i++) {
204 ptr += writepiece_SRC(cube.c[i], buf + ptr); 217 piece = get_corner(cube, i);
218 ptr += writepiece_SRC(piece, buf + ptr);
219 }
205 220
206 memcpy(buf+ptr-2, "},\n\t.e = {", 10); 221 memcpy(buf+ptr-2, "},\n\t.e = {", 10);
207 ptr += 8; 222 ptr += 8;
208 223
209 for (i = 0; i < 12; i++) 224 for (i = 0; i < 12; i++) {
210 ptr += writepiece_SRC(cube.e[i], buf + ptr); 225 piece = get_edge(cube, i);
226 ptr += writepiece_SRC(piece, buf + ptr);
227 }
211 228
212 memcpy(buf+ptr-2, "}\n}\0", 4); 229 memcpy(buf+ptr-2, "}\n}\0", 4);
213} 230}
@@ -364,7 +381,7 @@ permsign(uint8_t *a, int n)
364 381
365 for (i = 0; i < n; i++) 382 for (i = 0; i < n; i++)
366 for (j = i+1; j < n; j++) 383 for (j = i+1; j < n; j++)
367 ret += (a[i] & _pbits) > (a[j] & _pbits) ? 1 : 0; 384 ret += a[i] > a[j] ? 1 : 0;
368 385
369 return ret % 2; 386 return ret % 2;
370} 387}
@@ -372,14 +389,15 @@ permsign(uint8_t *a, int n)
372static bool 389static bool
373isconsistent(cube_t c) 390isconsistent(cube_t c)
374{ 391{
375 uint8_t i, p, e; 392 uint8_t i, p, e, piece;
376 bool found[12]; 393 bool found[12];
377 394
378 for (i = 0; i < 12; i++) 395 for (i = 0; i < 12; i++)
379 found[i] = false; 396 found[i] = false;
380 for (i = 0; i < 12; i++) { 397 for (i = 0; i < 12; i++) {
381 p = c.e[i] & _pbits; 398 piece = get_edge(c, i);
382 e = c.e[i] & ~_pbits; 399 p = piece & _pbits;
400 e = piece & _eobit;
383 if (p >= 12) 401 if (p >= 12)
384 goto inconsistent_ep; 402 goto inconsistent_ep;
385 if (e != 0 && e != _eobit) 403 if (e != 0 && e != _eobit)
@@ -393,8 +411,9 @@ isconsistent(cube_t c)
393 for (i = 0; i < 8; i++) 411 for (i = 0; i < 8; i++)
394 found[i] = false; 412 found[i] = false;
395 for (i = 0; i < 8; i++) { 413 for (i = 0; i < 8; i++) {
396 p = c.c[i] & _pbits; 414 piece = get_corner(c, i);
397 e = c.c[i] & ~_pbits; 415 p = piece & _pbits;
416 e = piece & _cobits;
398 if (p >= 8) 417 if (p >= 8)
399 goto inconsistent_cp; 418 goto inconsistent_cp;
400 if (e != 0 && e != _ctwist_cw && e != _ctwist_ccw) 419 if (e != 0 && e != _ctwist_cw && e != _ctwist_ccw)
@@ -432,7 +451,7 @@ inconsistent_co:
432bool 451bool
433issolvable(cube_t cube) 452issolvable(cube_t cube)
434{ 453{
435 int8_t i, eo, co; 454 uint8_t i, eo, co, piece, e[12], c[8];
436 455
437#ifdef DEBUG 456#ifdef DEBUG
438 if (!isconsistent(cube)) { 457 if (!isconsistent(cube)) {
@@ -441,18 +460,27 @@ issolvable(cube_t cube)
441 } 460 }
442#endif 461#endif
443 462
444 if (permsign(cube.e, 12) != permsign(cube.c, 8)) 463 for (i = 0; i < 12; i++)
464 e[i] = get_edge(cube, i) & _pbits;
465 for (i = 0; i < 8; i++)
466 c[i] = get_corner(cube, i) & _pbits;
467
468 if (permsign(e, 12) != permsign(c, 8))
445 goto issolvable_parity; 469 goto issolvable_parity;
446 470
447 eo = 0; 471 eo = 0;
448 for (i = 0; i < 12; i++) 472 for (i = 0; i < 12; i++) {
449 eo += (cube.e[i] & _eobit) >> _eoshift; 473 piece = get_edge(cube, i);
474 eo += (piece & _eobit) >> _eoshift;
475 }
450 if (eo % 2 != 0) 476 if (eo % 2 != 0)
451 goto issolvable_eo; 477 goto issolvable_eo;
452 478
453 co = 0; 479 co = 0;
454 for (i = 0; i < 8; i++) 480 for (i = 0; i < 8; i++) {
455 co += (cube.c[i] & _cobits) >> _coshift; 481 piece = get_corner(cube, i);
482 co += (piece & _cobits) >> _coshift;
483 }
456 if (co % 3 != 0) 484 if (co % 3 != 0)
457 goto issolvable_co; 485 goto issolvable_co;
458 486
@@ -478,6 +506,15 @@ issolvable_co:
478bool 506bool
479equal(cube_t cube1, cube_t cube2) 507equal(cube_t cube1, cube_t cube2)
480{ 508{
509#ifdef CUBE_AVX2
510 uint32_t mask;
511 __m256i cmp;
512
513 cmp = _mm256_cmpeq_epi8(cube1, cube2);
514 mask = _mm256_movemask_epi8(cmp);
515
516 return mask == 0xffffffffU;
517#else
481 uint8_t i; 518 uint8_t i;
482 519
483 for (i = 0; i < 12; i++) 520 for (i = 0; i < 12; i++)
@@ -489,6 +526,7 @@ equal(cube_t cube1, cube_t cube2)
489 return false; 526 return false;
490 527
491 return true; 528 return true;
529#endif
492} 530}
493 531
494bool 532bool
@@ -506,9 +544,6 @@ iserror(cube_t cube)
506cube_t 544cube_t
507move(cube_t c, move_t m) 545move(cube_t c, move_t m)
508{ 546{
509 cube_t ret;
510 uint8_t aux, auy, auz;
511
512#ifdef DEBUG 547#ifdef DEBUG
513 if (!isconsistent(c)) { 548 if (!isconsistent(c)) {
514 fprintf(stderr, "move error, inconsistent cube\n"); 549 fprintf(stderr, "move error, inconsistent cube\n");
@@ -516,154 +551,11 @@ move(cube_t c, move_t m)
516 } 551 }
517#endif 552#endif
518 553
519#define PERM4(r, i, j, k, l) \ 554#ifdef CUBE_AVX2
520 aux = r[i]; \ 555#include "_move_logic_avx2.c"
521 r[i] = r[l]; \ 556#else
522 r[l] = r[k]; \ 557#include "_move_logic_arr.c"
523 r[k] = r[j]; \
524 r[j] = aux;
525#define PERM22(r, i, j, k, l) \
526 aux = r[i]; \
527 r[i] = r[j]; \
528 r[j] = aux; \
529 aux = r[k]; \
530 r[k] = r[l]; \
531 r[l] = aux;
532#define CO(a, b) \
533 aux = (a & _cobits) + (b & _cobits); \
534 auy = (aux + _ctwist_cw) >> 2U; \
535 auz = (aux + auy) & _cobits2; \
536 a = (a & _pbits) | auz;
537#define CO4(r, i, j, k, l) \
538 CO(r[i], _ctwist_cw) \
539 CO(r[j], _ctwist_cw) \
540 CO(r[k], _ctwist_ccw) \
541 CO(r[l], _ctwist_ccw)
542#define EO4(r, i, j, k, l) \
543 r[i] ^= _eobit; \
544 r[j] ^= _eobit; \
545 r[k] ^= _eobit; \
546 r[l] ^= _eobit;
547
548 ret = c;
549
550 switch (m) {
551 case U:
552 PERM4(ret.e, _e_uf, _e_ul, _e_ub, _e_ur)
553 PERM4(ret.c, _c_ufr, _c_ufl, _c_ubl, _c_ubr)
554
555 return ret;
556 case U2:
557 PERM22(ret.e, _e_uf, _e_ub, _e_ul, _e_ur)
558 PERM22(ret.c, _c_ufr, _c_ubl, _c_ufl, _c_ubr)
559
560 return ret;
561 case U3:
562 PERM4(ret.e, _e_uf, _e_ur, _e_ub, _e_ul)
563 PERM4(ret.c, _c_ufr, _c_ubr, _c_ubl, _c_ufl)
564
565 return ret;
566 case D:
567 PERM4(ret.e, _e_df, _e_dr, _e_db, _e_dl)
568 PERM4(ret.c, _c_dfr, _c_dbr, _c_dbl, _c_dfl)
569
570 return ret;
571 case D2:
572 PERM22(ret.e, _e_df, _e_db, _e_dr, _e_dl)
573 PERM22(ret.c, _c_dfr, _c_dbl, _c_dbr, _c_dfl)
574
575 return ret;
576 case D3:
577 PERM4(ret.e, _e_df, _e_dl, _e_db, _e_dr)
578 PERM4(ret.c, _c_dfr, _c_dfl, _c_dbl, _c_dbr)
579
580 return ret;
581 case R:
582 PERM4(ret.e, _e_ur, _e_br, _e_dr, _e_fr)
583 PERM4(ret.c, _c_ufr, _c_ubr, _c_dbr, _c_dfr)
584
585 CO4(ret.c, _c_ubr, _c_dfr, _c_ufr, _c_dbr)
586
587 return ret;
588 case R2:
589 PERM22(ret.e, _e_ur, _e_dr, _e_fr, _e_br)
590 PERM22(ret.c, _c_ufr, _c_dbr, _c_ubr, _c_dfr)
591
592 return ret;
593 case R3:
594 PERM4(ret.e, _e_ur, _e_fr, _e_dr, _e_br)
595 PERM4(ret.c, _c_ufr, _c_dfr, _c_dbr, _c_ubr)
596
597 CO4(ret.c, _c_ubr, _c_dfr, _c_ufr, _c_dbr)
598
599 return ret;
600 case L:
601 PERM4(ret.e, _e_ul, _e_fl, _e_dl, _e_bl)
602 PERM4(ret.c, _c_ufl, _c_dfl, _c_dbl, _c_ubl)
603
604 CO4(ret.c, _c_ufl, _c_dbl, _c_dfl, _c_ubl)
605
606 return ret;
607 case L2:
608 PERM22(ret.e, _e_ul, _e_dl, _e_fl, _e_bl)
609 PERM22(ret.c, _c_ufl, _c_dbl, _c_ubl, _c_dfl)
610
611 return ret;
612 case L3:
613 PERM4(ret.e, _e_ul, _e_bl, _e_dl, _e_fl)
614 PERM4(ret.c, _c_ufl, _c_ubl, _c_dbl, _c_dfl)
615
616 CO4(ret.c, _c_ufl, _c_dbl, _c_dfl, _c_ubl)
617
618 return ret;
619 case F:
620 PERM4(ret.e, _e_uf, _e_fr, _e_df, _e_fl)
621 PERM4(ret.c, _c_ufr, _c_dfr, _c_dfl, _c_ufl)
622
623 EO4(ret.e, _e_uf, _e_fr, _e_df, _e_fl)
624 CO4(ret.c, _c_ufr, _c_dfl, _c_dfr, _c_ufl)
625
626 return ret;
627 case F2:
628 PERM22(ret.e, _e_uf, _e_df, _e_fr, _e_fl)
629 PERM22(ret.c, _c_ufr, _c_dfl, _c_ufl, _c_dfr)
630
631 return ret;
632 case F3:
633 PERM4(ret.e, _e_uf, _e_fl, _e_df, _e_fr)
634 PERM4(ret.c, _c_ufr, _c_ufl, _c_dfl, _c_dfr)
635
636 EO4(ret.e, _e_uf, _e_fr, _e_df, _e_fl)
637 CO4(ret.c, _c_ufr, _c_dfl, _c_dfr, _c_ufl)
638
639 return ret;
640 case B:
641 PERM4(ret.e, _e_ub, _e_bl, _e_db, _e_br)
642 PERM4(ret.c, _c_ubr, _c_ubl, _c_dbl, _c_dbr)
643
644 EO4(ret.e, _e_ub, _e_br, _e_db, _e_bl)
645 CO4(ret.c, _c_ubl, _c_dbr, _c_dbl, _c_ubr)
646
647 return ret;
648 case B2:
649 PERM22(ret.e, _e_ub, _e_db, _e_br, _e_bl)
650 PERM22(ret.c, _c_ubr, _c_dbl, _c_ubl, _c_dbr)
651
652 return ret;
653 case B3:
654 PERM4(ret.e, _e_ub, _e_br, _e_db, _e_bl)
655 PERM4(ret.c, _c_ubr, _c_dbr, _c_dbl, _c_ubl)
656
657 EO4(ret.e, _e_ub, _e_br, _e_db, _e_bl)
658 CO4(ret.c, _c_ubl, _c_dbr, _c_dbl, _c_ubr)
659
660 return ret;
661 default:
662#ifdef DEBUG
663 fprintf(stderr, "mover error, unknown move\n");
664#endif 558#endif
665 goto move_error;
666 }
667 559
668move_error: 560move_error:
669 return errorcube; 561 return errorcube;
@@ -672,8 +564,9 @@ move_error:
672cube_t 564cube_t
673inverse(cube_t c) 565inverse(cube_t c)
674{ 566{
567 /* TODO: optimize for avx2 */
675 uint8_t i, piece, orien; 568 uint8_t i, piece, orien;
676 cube_t ret = {0}; 569 cube_t ret = zerocube;
677 570
678#ifdef DEBUG 571#ifdef DEBUG
679 if (!isconsistent(c)) { 572 if (!isconsistent(c)) {
@@ -683,15 +576,15 @@ inverse(cube_t c)
683#endif 576#endif
684 577
685 for (i = 0; i < 12; i++) { 578 for (i = 0; i < 12; i++) {
686 piece = c.e[i & _pbits]; 579 piece = get_edge(c, i);
687 orien = piece & _eobit; 580 orien = piece & _eobit;
688 ret.e[piece & _pbits] = i | orien; 581 set_edge(&ret, piece & _pbits, i | orien);
689 } 582 }
690 583
691 for (i = 0; i < 8; i++) { 584 for (i = 0; i < 8; i++) {
692 piece = c.c[i & _pbits]; 585 piece = get_corner(c, i);
693 orien = ((piece << 1) | (piece >> 1)) & _cobits2; 586 orien = ((piece << 1) | (piece >> 1)) & _cobits2;
694 ret.c[piece & _pbits] = i | orien; 587 set_corner(&ret, piece & _pbits, i | orien);
695 } 588 }
696 589
697 return ret; 590 return ret;
@@ -700,8 +593,9 @@ inverse(cube_t c)
700cube_t 593cube_t
701compose(cube_t c1, cube_t c2) 594compose(cube_t c1, cube_t c2)
702{ 595{
703 uint8_t i, piece, orien, aux, auy; 596 /* TODO: optimize for avx2 */
704 cube_t ret = {0}; 597 uint8_t i, piece1, piece2, p, orien, aux, auy;
598 cube_t ret = zerocube;
705 599
706#ifdef DEBUG 600#ifdef DEBUG
707 if (!isconsistent(c1) || !isconsistent(c2)) { 601 if (!isconsistent(c1) || !isconsistent(c2)) {
@@ -711,17 +605,21 @@ compose(cube_t c1, cube_t c2)
711#endif 605#endif
712 606
713 for (i = 0; i < 12; i++) { 607 for (i = 0; i < 12; i++) {
714 piece = c2.e[i] & _pbits; 608 piece2 = get_edge(c2, i);
715 orien = (c2.e[i] ^ c1.e[piece]) & _eobit; 609 p = piece2 & _pbits;
716 ret.e[i] = (c1.e[piece] & _pbits) | orien; 610 piece1 = get_edge(c1, p);
611 orien = (piece2 ^ piece1) & _eobit;
612 set_edge(&ret, i, (piece1 & _pbits) | orien);
717 } 613 }
718 614
719 for (i = 0; i < 8; i++) { 615 for (i = 0; i < 8; i++) {
720 piece = c2.c[i] & _pbits; 616 piece2 = get_corner(c2, i);
721 aux = (c2.c[i] & _cobits) + (c1.c[piece] & _cobits); 617 p = piece2 & _pbits;
618 piece1 = get_corner(c1, p);
619 aux = (piece2 & _cobits) + (piece1 & _cobits);
722 auy = (aux + _ctwist_cw) >> 2U; 620 auy = (aux + _ctwist_cw) >> 2U;
723 orien = (aux + auy) & _cobits2; 621 orien = (aux + auy) & _cobits2;
724 ret.c[i] = (c1.c[piece] & _pbits) | orien; 622 set_corner(&ret, i, (piece1 & _pbits) | orien);
725 } 623 }
726 624
727 return ret; 625 return ret;
@@ -730,14 +628,16 @@ compose(cube_t c1, cube_t c2)
730static cube_t 628static cube_t
731flipallcorners(cube_t c) 629flipallcorners(cube_t c)
732{ 630{
631/* TODO: optimize for avx2, can be a couple of instructions */
632
733 uint8_t i, piece, orien; 633 uint8_t i, piece, orien;
734 cube_t ret; 634 cube_t ret;
735 635
736 ret = c; 636 ret = c;
737 for (i = 0; i < 8; i++) { 637 for (i = 0; i < 8; i++) {
738 piece = ret.c[i]; 638 piece = get_corner(c, i);
739 orien = ((piece << 1) | (piece >> 1)) & _cobits2; 639 orien = ((piece << 1) | (piece >> 1)) & _cobits2;
740 ret.c[i] = (piece & _pbits) | orien; 640 set_corner(&ret, i, (piece & _pbits) | orien);
741 } 641 }
742 642
743 return ret; 643 return ret;
@@ -746,8 +646,6 @@ flipallcorners(cube_t c)
746cube_t 646cube_t
747transform(cube_t c, trans_t t) 647transform(cube_t c, trans_t t)
748{ 648{
749#include "_trans_move_arr.c"
750
751 cube_t ret; 649 cube_t ret;
752 650
753#ifdef DEBUG 651#ifdef DEBUG
@@ -761,6 +659,12 @@ transform(cube_t c, trans_t t)
761 } 659 }
762#endif 660#endif
763 661
662#ifdef CUBE_AVX2
663#include "_trans_move_avx2.c"
664#else
665#include "_trans_move_arr.c"
666#endif
667
764 ret = compose(solvedcube, trans_move_cube[t]); 668 ret = compose(solvedcube, trans_move_cube[t]);
765 ret = compose(ret, c); 669 ret = compose(ret, c);
766 ret = compose(ret, trans_move_cube_inverse[t]); 670 ret = compose(ret, trans_move_cube_inverse[t]);

Generated with cgit - Back to sebastiano.tronto.net