aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2023-11-03 23:13:05 +0100
committerSebastiano Tronto <sebastiano@tronto.net>2023-11-03 23:26:29 +0100
commitade2ed050a2d472b4dd01e30666f5e7ec5030724 (patch)
treebab29caba8fb2171348fb664d6098eb77d155a53
parent9b1c9371333e20611ec5422e660ebec7e66c4261 (diff)
downloadnissy-core-ade2ed050a2d472b4dd01e30666f5e7ec5030724.tar.gz
nissy-core-ade2ed050a2d472b4dd01e30666f5e7ec5030724.zip
Moves work with avx2, fixed some stuff
Diffstat (limited to '')
-rw-r--r--Makefile4
-rw-r--r--README.md9
-rwxr-xr-xbenchmark/bench.sh7
-rw-r--r--src/_trans_avx2.c2
-rw-r--r--src/cube.c146
-rw-r--r--src/cube.h1
-rw-r--r--test/00_basic/basic_tests.c1
-rwxr-xr-xtest/test.sh8
8 files changed, 117 insertions, 61 deletions
diff --git a/Makefile b/Makefile
index 54848ac..082b740 100644
--- a/Makefile
+++ b/Makefile
@@ -12,9 +12,9 @@ clean:
12 rm -rf *.o 12 rm -rf *.o
13 13
14test: debugcube.o 14test: debugcube.o
15 ./test/test.sh 15 CUBETYPE=${CUBETYPE} ./test/test.sh
16 16
17benchmark: cube.o 17benchmark: cube.o
18 ./benchmark/bench.sh 18 CUBETYPE=${CUBETYPE} ./benchmark/bench.sh
19 19
20.PHONY: all clean test benchmark 20.PHONY: all clean test benchmark
diff --git a/README.md b/README.md
index 571a859..4aa18c7 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,13 @@ $ make test
15 15
16### Make AVX2 work 16### Make AVX2 work
17 17
18* fix base get_ and set_ macros (constant arguments?) 18* fix inverse, flipallcorners
19
20### Cleanup / refactor
21
22* see planner
23* change all set_epi to setr_epi
24* change epi8 to epi64x (shorter!)
19 25
20### Documentation and interface 26### Documentation and interface
21 27
@@ -41,6 +47,7 @@ $ make test
41 end to check that it is actually solved. 47 end to check that it is actually solved.
42* see if vcube's method to flip all corners is better 48* see if vcube's method to flip all corners is better
43* find a better way for computing the inverse? 49* find a better way for computing the inverse?
50* Improve avx2 instructions in general
44 51
45## Internal representation of the cube 52## Internal representation of the cube
46 53
diff --git a/benchmark/bench.sh b/benchmark/bench.sh
index 839515a..882c836 100755
--- a/benchmark/bench.sh
+++ b/benchmark/bench.sh
@@ -1,10 +1,15 @@
1#!/bin/sh 1#!/bin/sh
2 2
3CC="cc -std=c99 -pthread -O3 -D$CUBETYPE"
4if [ "$CUBETYPE" = "CUBE_AVX2" ]; then
5 CC="$CC -mavx2"
6fi
7
3BENCHBIN="benchmark/run" 8BENCHBIN="benchmark/run"
4BENCHDIR="benchmark/results" 9BENCHDIR="benchmark/results"
5CUBEOBJ="cube.o" 10CUBEOBJ="cube.o"
6 11
7cc -std=c99 -pthread -O3 -o $BENCHBIN benchmark/bench.c $CUBEOBJ || exit 1; 12$CC -o $BENCHBIN benchmark/bench.c $CUBEOBJ || exit 1;
8 13
9d="$(date +'%Y-%m-%d-%H-%M-%S')" 14d="$(date +'%Y-%m-%d-%H-%M-%S')"
10mkdir -p "$BENCHDIR" 15mkdir -p "$BENCHDIR"
diff --git a/src/_trans_avx2.c b/src/_trans_avx2.c
index 29ee942..e80bf79 100644
--- a/src/_trans_avx2.c
+++ b/src/_trans_avx2.c
@@ -7,7 +7,7 @@ flipallcorners(cube_t c)
7 shright = _mm256_srli_si256(c, 1); 7 shright = _mm256_srli_si256(c, 1);
8 summed = _mm256_or_si256(shleft, shright); 8 summed = _mm256_or_si256(shleft, shright);
9 newco = _mm256_and_si256(summed, _co_avx2); 9 newco = _mm256_and_si256(summed, _co_avx2);
10 cleanco = _mm256_andnot_si256_(c, _co_avx2); 10 cleanco = _mm256_andnot_si256(c, _co_avx2);
11 ret = _mm256_and_si256(cleanco, newco); 11 ret = _mm256_and_si256(cleanco, newco);
12 12
13 return ret; 13 return ret;
diff --git a/src/cube.c b/src/cube.c
index 401895e..768c1bb 100644
--- a/src/cube.c
+++ b/src/cube.c
@@ -6,10 +6,6 @@
6#include <stdio.h> 6#include <stdio.h>
7#endif 7#endif
8 8
9#ifdef AVX2
10#include <immintrin.h>
11#endif
12
13#include "cube.h" 9#include "cube.h"
14 10
15#define U 0U 11#define U 0U
@@ -118,6 +114,11 @@
118#define _eflip 0x10U 114#define _eflip 0x10U
119#define _error 0xFFU 115#define _error 0xFFU
120 116
117#define get_edge(cube, i) (cube).e[(i)]
118#define get_corner(cube, i) (cube).c[(i)]
119#define set_edge(cube, i, p) (cube).e[(i)] = (p)
120#define set_corner(cube, i, p) (cube).c[(i)] = (p)
121
121cube_arr_t solvedcube_arr = { 122cube_arr_t solvedcube_arr = {
122 .c = {0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0}, 123 .c = {0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0},
123 .e = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, 0, 0} 124 .e = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, 0, 0}
@@ -126,40 +127,54 @@ cube_arr_t zerocube_arr = { .e = {0}, .c = {0} };
126 127
127#ifdef CUBE_AVX2 128#ifdef CUBE_AVX2
128 129
129#define _co_avx2 _mm256_set_epi64x(0, 0xF0F0F0F0F0F0F0F0, 0, 0) 130#define _co_avx2 _mm256_set_epi8( \
130#define _eo_avx2 _mm256_set_epi64x(0, 0, 0xF0F0F0F0, 0xF0F0F0F0F0F0F0F0) 131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
131#define _c _mm256_set_epi64x(0, 0, 0, 0xFF) 132 0, 0, 0, 0, 0, 0, 0, 0, \
132#define _e _mm256_set_epi64x(0, 0xFF, 0, 0) 133 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70)
134#define _eo_avx2 _mm256_set_epi8( \
135 0, 0, 0, 0, 0x70, 0x70, 0x70, 0x70, \
136 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, \
137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
133#define setsolved(cube) cube = _mm256_loadu_si256((__m256i_u *)&solvedcube_arr) 138#define setsolved(cube) cube = _mm256_loadu_si256((__m256i_u *)&solvedcube_arr)
134#define setzero(cube) cube = _mm256_setzero_si256() 139#define setzero(cube) cube = _mm256_setzero_si256()
135/* TODO: in the next 4 macros, all 0 should be i, but must be constant! */
136#define get_edge(cube, i) _mm256_extract_epi8(cube, 0+16)
137#define get_corner(cube, i) _mm256_extract_epi8(cube, 0)
138#define set_edge(cube, i, p) _mm256_or_si256( \
139 _mm256_andnot_si256(cube, _mm256_slli_si256(_e, 0)), \
140 _mm256_and_si256(_mm256_set1_epi8(p), _mm256_slli_si256(_e, 0)))
141#define set_corner(cube, i, p) _mm256_or_si256( \
142 _mm256_andnot_si256(cube, _mm256_slli_si256(_c, 0)), \
143 _mm256_and_si256(_mm256_set1_epi8(p), _mm256_slli_si256(_c, 0)))
144 140
145#include "_moves_avx2.c" 141#include "_moves_avx2.c"
146#include "_trans_avx2.c" 142#include "_trans_avx2.c"
147 143
144static cube_t
145arrtocube(cube_arr_t a)
146{
147 return _mm256_loadu_si256((__m256i_u *)&a);
148}
149
150static void
151cubetoarr(cube_t c, cube_arr_t *a)
152{
153 _mm256_storeu_si256((__m256i_u *)a, c);
154}
155
148#else 156#else
149 157
150#define setsolved(cube) cube = solvedcube_arr 158#define setsolved(cube) cube = solvedcube_arr
151#define setzero(cube) cube = zerocube_arr 159#define setzero(cube) cube = zerocube_arr
152#define get_edge(cube, i) (cube).e[(i)] 160
153#define get_corner(cube, i) (cube).c[(i)] 161static cube_t
154#define set_edge(cube, i, p) (cube).e[(i)] = (p) 162arrtocube(cube_arr_t a)
155#define set_corner(cube, i, p) (cube).c[(i)] = (p) 163{
164 return a;
165}
166
167static void
168cubetoarr(cube_t c, cube_arr_t *a)
169{
170 memcpy(a, &c, sizeof(cube_t));
171}
156 172
157#include "_moves_arr.c" 173#include "_moves_arr.c"
158#include "_trans_arr.c" 174#include "_trans_arr.c"
159 175
160#endif 176#endif
161 177
162
163static char *cornerstr[] = { 178static char *cornerstr[] = {
164 [_c_ufr] = "UFR", 179 [_c_ufr] = "UFR",
165 [_c_ubl] = "UBL", 180 [_c_ubl] = "UBL",
@@ -279,10 +294,10 @@ static uint8_t readep(char *);
279static uint8_t readmove(char); 294static uint8_t readmove(char);
280static uint8_t readmodifier(char); 295static uint8_t readmodifier(char);
281static cube_t readcube_H48(char *); 296static cube_t readcube_H48(char *);
282static void writecube_AVX(cube_t, char *); 297static void writecube_AVX(cube_arr_t, char *);
283static void writecube_H48(cube_t, char *); 298static void writecube_H48(cube_arr_t, char *);
284static int writepiece_SRC(uint8_t, char *); 299static int writepiece_SRC(uint8_t, char *);
285static void writecube_SRC(cube_t, char *); 300static void writecube_SRC(cube_arr_t, char *);
286static int permsign(uint8_t *, int); 301static int permsign(uint8_t *, int);
287 302
288cube_t 303cube_t
@@ -367,10 +382,10 @@ readcube_H48(char *buf)
367{ 382{
368 int i; 383 int i;
369 uint8_t piece, orient; 384 uint8_t piece, orient;
370 cube_t ret, err; 385 cube_arr_t ret = {0};
386 cube_t err;
371 char *b; 387 char *b;
372 388
373 setzero(ret);
374 setzero(err); 389 setzero(err);
375 b = buf; 390 b = buf;
376 391
@@ -397,7 +412,7 @@ readcube_H48(char *buf)
397 set_corner(ret, i, piece | orient); 412 set_corner(ret, i, piece | orient);
398 } 413 }
399 414
400 return ret; 415 return arrtocube(ret);
401} 416}
402 417
403cube_t 418cube_t
@@ -424,7 +439,7 @@ readcube(format_t format, char *buf)
424} 439}
425 440
426static void 441static void
427writecube_AVX(cube_t cube, char *buf) 442writecube_AVX(cube_arr_t cube, char *buf)
428{ 443{
429 int i, ptr; 444 int i, ptr;
430 uint8_t piece; 445 uint8_t piece;
@@ -448,9 +463,8 @@ writecube_AVX(cube_t cube, char *buf)
448 memcpy(buf+ptr-2, "\n)\0", 3); 463 memcpy(buf+ptr-2, "\n)\0", 3);
449} 464}
450 465
451
452static void 466static void
453writecube_H48(cube_t cube, char *buf) 467writecube_H48(cube_arr_t cube, char *buf)
454{ 468{
455 uint8_t piece, perm, orient; 469 uint8_t piece, perm, orient;
456 int i; 470 int i;
@@ -502,7 +516,7 @@ writepiece_SRC(uint8_t piece, char *buf)
502} 516}
503 517
504static void 518static void
505writecube_SRC(cube_t cube, char *buf) 519writecube_SRC(cube_arr_t cube, char *buf)
506{ 520{
507 int i, ptr; 521 int i, ptr;
508 uint8_t piece; 522 uint8_t piece;
@@ -529,6 +543,7 @@ writecube_SRC(cube_t cube, char *buf)
529void 543void
530writecube(format_t format, cube_t cube, char *buf) 544writecube(format_t format, cube_t cube, char *buf)
531{ 545{
546 cube_arr_t a;
532 char *errormsg; 547 char *errormsg;
533 size_t len; 548 size_t len;
534 549
@@ -537,15 +552,17 @@ writecube(format_t format, cube_t cube, char *buf)
537 goto writecube_error; 552 goto writecube_error;
538 } 553 }
539 554
555 cubetoarr(cube, &a);
556
540 switch (format) { 557 switch (format) {
541 case AVX: 558 case AVX:
542 writecube_AVX(cube, buf); 559 writecube_AVX(a, buf);
543 break; 560 break;
544 case H48: 561 case H48:
545 writecube_H48(cube, buf); 562 writecube_H48(a, buf);
546 break; 563 break;
547 case SRC: 564 case SRC:
548 writecube_SRC(cube, buf); 565 writecube_SRC(a, buf);
549 break; 566 break;
550 default: 567 default:
551 errormsg = "ERROR: cannot write cube in the given format"; 568 errormsg = "ERROR: cannot write cube in the given format";
@@ -687,11 +704,14 @@ permsign(uint8_t *a, int n)
687} 704}
688 705
689static bool 706static bool
690isconsistent(cube_t c) 707isconsistent(cube_t cube)
691{ 708{
709 cube_arr_t c;
692 uint8_t i, p, e, piece; 710 uint8_t i, p, e, piece;
693 bool found[12]; 711 bool found[12];
694 712
713 cubetoarr(cube, &c);
714
695 for (i = 0; i < 12; i++) 715 for (i = 0; i < 12; i++)
696 found[i] = false; 716 found[i] = false;
697 for (i = 0; i < 12; i++) { 717 for (i = 0; i < 12; i++) {
@@ -751,7 +771,8 @@ inconsistent_co:
751bool 771bool
752issolvable(cube_t cube) 772issolvable(cube_t cube)
753{ 773{
754 uint8_t i, eo, co, piece, e[12], c[8]; 774 cube_arr_t c;
775 uint8_t i, eo, co, piece, edges[12], corners[8];
755 776
756#ifdef DEBUG 777#ifdef DEBUG
757 if (!isconsistent(cube)) { 778 if (!isconsistent(cube)) {
@@ -760,17 +781,19 @@ issolvable(cube_t cube)
760 } 781 }
761#endif 782#endif
762 783
784 cubetoarr(cube, &c);
785
763 for (i = 0; i < 12; i++) 786 for (i = 0; i < 12; i++)
764 e[i] = get_edge(cube, i) & _pbits; 787 edges[i] = get_edge(c, i) & _pbits;
765 for (i = 0; i < 8; i++) 788 for (i = 0; i < 8; i++)
766 c[i] = get_corner(cube, i) & _pbits; 789 corners[i] = get_corner(c, i) & _pbits;
767 790
768 if (permsign(e, 12) != permsign(c, 8)) 791 if (permsign(edges, 12) != permsign(corners, 8))
769 goto issolvable_parity; 792 goto issolvable_parity;
770 793
771 eo = 0; 794 eo = 0;
772 for (i = 0; i < 12; i++) { 795 for (i = 0; i < 12; i++) {
773 piece = get_edge(cube, i); 796 piece = get_edge(c, i);
774 eo += (piece & _eobit) >> _eoshift; 797 eo += (piece & _eobit) >> _eoshift;
775 } 798 }
776 if (eo % 2 != 0) 799 if (eo % 2 != 0)
@@ -778,7 +801,7 @@ issolvable(cube_t cube)
778 801
779 co = 0; 802 co = 0;
780 for (i = 0; i < 8; i++) { 803 for (i = 0; i < 8; i++) {
781 piece = get_corner(cube, i); 804 piece = get_corner(c, i);
782 co += (piece & _cobits) >> _coshift; 805 co += (piece & _cobits) >> _coshift;
783 } 806 }
784 if (co % 3 != 0) 807 if (co % 3 != 0)
@@ -909,7 +932,6 @@ move_error:
909cube_t 932cube_t
910inverse(cube_t c) 933inverse(cube_t c)
911{ 934{
912 /* TODO: optimize for avx2 */
913 cube_t ret; 935 cube_t ret;
914 936
915#ifdef DEBUG 937#ifdef DEBUG
@@ -926,7 +948,7 @@ inverse(cube_t c)
926 * [1] https://github.com/Voltara/vcube 948 * [1] https://github.com/Voltara/vcube
927 * [2] http://wwwhomes.uni-bielefeld.de/achim/addition_chain.html 949 * [2] http://wwwhomes.uni-bielefeld.de/achim/addition_chain.html
928 */ 950 */
929 cube_t v3, vi; 951 cube_t v3, vi, vo, vp;
930 952
931 v3 = _mm256_shuffle_epi8(c, c); 953 v3 = _mm256_shuffle_epi8(c, c);
932 v3 = _mm256_shuffle_epi8(v3, c); 954 v3 = _mm256_shuffle_epi8(v3, c);
@@ -945,7 +967,12 @@ inverse(cube_t c)
945 vi = _mm256_shuffle_epi8(vi, vi); 967 vi = _mm256_shuffle_epi8(vi, vi);
946 vi = _mm256_shuffle_epi8(vi, v3); 968 vi = _mm256_shuffle_epi8(vi, v3);
947 vi = _mm256_shuffle_epi8(vi, vi); 969 vi = _mm256_shuffle_epi8(vi, vi);
948 ret = _mm256_shuffle_epi8(vi, c); 970 vi = _mm256_shuffle_epi8(vi, c);
971
972 vo = _mm256_and_si256(c, _mm256_or_si256(_eo_avx2, _co_avx2));
973 vo = _mm256_shuffle_epi8(vo, vi);
974 vp = _mm256_andnot_si256(_mm256_or_si256(_eo_avx2, _co_avx2), vi);
975 ret = _mm256_or_si256(vp, vo);
949 976
950 return flipallcorners(ret); 977 return flipallcorners(ret);
951#else 978#else
@@ -983,19 +1010,30 @@ inline_compose(cube_t c1, cube_t c2)
983#endif 1010#endif
984 1011
985#ifdef CUBE_AVX2 1012#ifdef CUBE_AVX2
986 cube_t shuf, eo, eodone, co2, aux, auy1, auy2, cw, auz1, auz2, coclean; 1013 cube_t s, eo2, ed, co1, co2, aux, auy1, auy2, cw, cwccw, auz1, auz2,
1014 coclean;
987 1015
1016 eo2 = _mm256_and_si256(c2, _eo_avx2);
1017 s = _mm256_shuffle_epi8(c1, c2);
1018 ed = _mm256_xor_si256(s, eo2);
1019 co1 = _mm256_and_si256(s, _co_avx2);
988 co2 = _mm256_and_si256(c2, _co_avx2); 1020 co2 = _mm256_and_si256(c2, _co_avx2);
989 eo = _mm256_and_si256(c2, _eo_avx2); 1021 aux = _mm256_add_epi8(co1, co2);
990 shufd = _mm256_shuffle_epi8(c1, c2); 1022 cw = _mm256_set_epi8(
991 eodone = _mm256_(shufd, eo); 1023 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
992 aux = _mm256_add_epi8(c1, co2); 1024 0, 0, 0, 0, 0, 0, 0, 0,
993 cw = _mm256_set_epi64x(0, 0x2020202020202020, 0, 0); 1025 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
1026 );
994 auy1 = _mm256_add_epi8(aux, cw); 1027 auy1 = _mm256_add_epi8(aux, cw);
995 auy2 = _mm256_srli_si256(auy1, 2); 1028 auy2 = _mm256_srli_epi32(auy1, 2);
996 auz1 = _mm256_add_epi8(aux, auy2); 1029 auz1 = _mm256_add_epi8(aux, auy2);
997 auz2 = _mm256_and_si256(auz1, _co_avx2); 1030 cwccw = _mm256_set_epi8(
998 coclean = _mm256_andnot_si256(eodone, _co_avx2); 1031 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1032 0, 0, 0, 0, 0, 0, 0, 0,
1033 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60
1034 );
1035 auz2 = _mm256_and_si256(auz1, cwccw);
1036 coclean = _mm256_andnot_si256(_co_avx2, ed);
999 ret = _mm256_or_si256(coclean, auz2); 1037 ret = _mm256_or_si256(coclean, auz2);
1000#else 1038#else
1001 uint8_t i, piece1, piece2, p, orien, aux, auy; 1039 uint8_t i, piece1, piece2, p, orien, aux, auy;
diff --git a/src/cube.h b/src/cube.h
index a40b8a0..468b0ca 100644
--- a/src/cube.h
+++ b/src/cube.h
@@ -3,6 +3,7 @@ typedef struct {
3 uint8_t e[16]; 3 uint8_t e[16];
4} cube_arr_t; 4} cube_arr_t;
5#ifdef CUBE_AVX2 5#ifdef CUBE_AVX2
6#include <immintrin.h>
6typedef __m256i cube_t; 7typedef __m256i cube_t;
7#else 8#else
8typedef cube_arr_t cube_t; 9typedef cube_arr_t cube_t;
diff --git a/test/00_basic/basic_tests.c b/test/00_basic/basic_tests.c
index ddfecb4..5f5df6b 100644
--- a/test/00_basic/basic_tests.c
+++ b/test/00_basic/basic_tests.c
@@ -14,6 +14,7 @@ check(cube_t cube, char *name)
14void 14void
15check2(cube_t cube1, char *name1, cube_t cube2, char *name2) 15check2(cube_t cube1, char *name1, cube_t cube2, char *name2)
16{ 16{
17fprintf(stderr, "check2 %s %s\n", name1, name2);
17 printf("%s and %s are%s equal\n", name1, name2, 18 printf("%s and %s are%s equal\n", name1, name2,
18 equal(cube1, cube2) ? "" : " NOT"); 19 equal(cube1, cube2) ? "" : " NOT");
19} 20}
diff --git a/test/test.sh b/test/test.sh
index 9e064b2..1ee972d 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -1,10 +1,14 @@
1#!/bin/sh 1#!/bin/sh
2 2
3CC="cc -DDEBUG -std=c99 -pthread -pedantic -Wall -Wextra \ 3CC="cc -DDEBUG -std=c99 -pthread -pedantic -Wall -Wextra \
4 -Wno-unused-parameter -Wno-unused-function -g3" 4 -Wno-unused-parameter -Wno-unused-function -g3 -D$CUBETYPE"
5if [ $(uname) != "OpenBSD" ]; then 5if [ "$CUBETYPE" = "CUBE_AVX2" ]; then
6 CC="$CC -mavx2"
7fi
8if [ "$(uname)" != "OpenBSD" ]; then
6 CC="$CC -fsanitize=address -fsanitize=undefined" 9 CC="$CC -fsanitize=address -fsanitize=undefined"
7fi 10fi
11
8TESTBIN="test/run" 12TESTBIN="test/run"
9TESTOUT="test/last.out" 13TESTOUT="test/last.out"
10TESTERR="test/last.err" 14TESTERR="test/last.err"

Generated with cgit - Back to sebastiano.tronto.net