Verbesserungswürdiger Assembler Code???
-
EDIT: Alles falsch! Du sucht ja nicht bestimmte Werte, sondern welche der vielen Bitmaskee paßt. Alles vergebens. Ich bin ja soo doof.
Hab ein Testprogramm geschieben
#include <iostream> #include <windows.h> using namespace std; typedef unsigned long long u64; typedef unsigned int u32; bool test(u64 x) { u32 t=u32(x)^u32(x>>32); u32 y=(t*2175734977u)>>29; static u64 table[]={ 0x10204ull, 0x820020000ull, 0x20020800ull, 0x10204ull, 0x4210000000ull, 0x10204ull, 0x20820ull, 0x20820000000ull, }; return x==table[y]; } u64 goodValues[]={ 0x20820000000ull, 0x820020000ull, 0x20020800ull, 0x20820ull, 0x10204ull, 0x4210000000ull, }; int main() { size_t const goodValuesSize=sizeof(goodValues)/sizeof(goodValues[0]); size_t const tableSizeBits=3; size_t const tableSize=1<<tableSizeBits; u64 table[tableSize]; u32 const step=2654435761u; for (u32 a=step;a!=0;a+=step) { if (a%1048576==0) cout<<"checking "<<a<<'\n'; bool seen[tableSize]={}; for (size_t i=0;i!=goodValuesSize;++i) { u64 x=goodValues[i]; u32 t=u32(x)^u32(x>>(32-tableSizeBits)); u32 y=(t*a)>>29; // cout<<x<<' '<<y<<'\n'; // Sleep(1000); if (seen[y]) goto collission; table[y]=x; seen[y]=true; } cout<<"found\n"; cout<<"\ty=(t*"<<a<<"u)>>"<<32-tableSizeBits<<";\n"; cout<<hex; cout<<"\tstatic u64 table[]={\n"; for (size_t i=0;i!=tableSize;++i) { if (seen[i]) cout<<"\t\t0x"<<table[i]<<"ull,\n"; else cout<<"\t\t0x"<<table[0]<<"ull,\n"; } cout<<"\t};\n"; break; collission: ; } cout<<test(1)<<'\n'; return 0; }
Es fand
bool test(u64 x) { u32 t=u32(x)^u32(x>>32); u32 y=(t*2175734977u)>>29; static u64 table[]={ 0x10204ull, 0x820020000ull, 0x20020800ull, 0x10204ull, 0x4210000000ull, 0x10204ull, 0x20820ull, 0x20820000000ull, }; return x==table[y]; }
Code aus dem Compilat von GCC kopiert:
LFE652: .text .p2align 4,,15 .globl __Z4testy .def __Z4testy; .scl 2; .type 32; .endef __Z4testy: LFB991: pushl %ebp LCFI2: movl %esp, %ebp LCFI3: movl 12(%ebp), %edx movl 8(%ebp), %ecx movl %edx, %eax xorl %ecx, %eax imull $-2119232319, %eax, %eax shrl $29, %eax xorl __ZZ4testyE5table(,%eax,8), %ecx xorl __ZZ4testyE5table+4(,%eax,8), %edx leave orl %edx, %ecx sete %al ret LFE991:
nur ein MUL und kein bedingter Sprung.
Hunderte von Werten werden wohl eine kompliziertere Hash-Funktion als nur u32 t=u32(x)^u32(x>>32); u32 y=(t*2175734977u)>>29; brauchen, aber wer weiß, vielleicht nur wenige Takte schlimmer.Wenns kein AMD ist, ist vielleicht
u32 y=(t*40004u)>>29; static u64 table[]={ 0x10204ull, 0x20820ull, 0x4210000000ull, 0x10204ull, 0x820020000ull, 0x20020800ull, 0x20820000000ull, 0x10204ull, };
netter mit
__Z4testy: LFB991: pushl %ebp LCFI2: movl %esp, %ebp LCFI3: pushl %ebx LCFI4: movl 8(%ebp), %ebx movl 12(%ebp), %ecx movl %ecx, %eax xorl %ebx, %eax leal (%eax,%eax,4), %edx leal (%edx,%edx,4), %edx leal (%edx,%edx,4), %edx leal (%edx,%edx,4), %edx sall $4, %edx leal (%edx,%eax), %eax sall $2, %eax shrl $29, %eax xorl __ZZ4testyE5table(,%eax,8), %ebx xorl __ZZ4testyE5table+4(,%eax,8), %ecx orl %ecx, %ebx sete %al popl %ebx leave ret LFE991:
-
Wow, Volkard, du sollst mir nicht das ganze Programm schreiben
.Ich will auch noch was machen. Naja, das was ich jetzt mal versuche, sieht in etwa so aus(Hoffentlich ist das kein kompletter Blödsinn):
mov eax,dword ptr [_Feld1] mov edx,dword ptr [_Feld1+4] not eax not edx test eax,536870912 jnz @7 test edx,520 jz @exittrue @7: test eax,537001984 jnz @8 test edx,8 jz @exittrue @8: test eax,537004032 jz @exittrue @9: test eax, 133152 jz @exittrue @10: test eax,66052 jz @exittrue @11: test eax,537001984 jnz @exitfalse test edx,8 jz @exittrue
Das entspräche diesem C-Code (Hoffe ich):
if(!(x & 0x20820000000i64 && x & 0x820020000i64 && x & 0x20020800i64 && x & 0x20820i64 && x & 0x10204i64 && x & 0x4210000000i64)) return true;
-
Franz von und zu Assisi schrieb:
@8: test eax,537004032 jz @exittrue @9: test eax, 133152 jz @exittrue @10: test eax,66052 jz @exittrue
Damit begehst DU meinen Fehler, fürchte ich, und Du testest nicht mehr, ob unter anderem diese 3 Bits gesetzt sind, sondern ob nur genau diese 3 Bits gesetzt sind.
-
volkard schrieb:
Franz von und zu Assisi schrieb:
@8: test eax,537004032 jz @exittrue @9: test eax, 133152 jz @exittrue @10: test eax,66052 jz @exittrue
Damit begehst DU meinen Fehler, fürchte ich, und Du testest nicht mehr, ob unter anderem diese 3 Bits gesetzt sind, sondern ob nur genau diese 3 Bits gesetzt sind.
Ne, meine Lösung müsste richtig sein. Ich hab sie mit allen relevanten Spielstellungen getestet. Ich hab meinen Assembler-Code auch auf Laufzeit getestet, erstaunlicherweise ist der aber langsamer als der reine C-Code. Daher gehe ich davon aus, dass der Assembler-Code, den der Compiler ausspuckt, noch nicht optimiert ist, die Optimierung also zu einem späteren Zeitpunkt erfolgt. Daher macht eine Optimierung von Hand meiner Meinung nach keinen Sinn mehr (außer im C-Code), obwohl meine Lösung sicherlich noch nicht optimal ist.
Trotzdem hat Campers Ideebool SpielBeenden1() { i64 x = ~Feld1; return !( x & 0x20820000000i64 && x & 0x00820020000i64 && x & 0x00020020800i64 && x & 0x00000020820i64 && x & 0x00000010204i64 && x & 0x04210000000i64 ); }
einiges gebracht (5-10% Laufzeitvorteil). Und damit kann ich ganz gut leben. Meiner Meinung nach kann der Thread jetzt auch geschlossen werden.
Vielen Dank an alle Helfer
-
volkard schrieb:
EDIT: Alles falsch! Du sucht ja nicht bestimmte Werte, sondern welche der vielen Bitmaskee paßt. Alles vergebens. Ich bin ja soo doof.
Der Ansatz ist vielleicht trotzdem nicht so doof. Jedenfalls die Faltung könnte brauchbar sein:
Wenn im echten Programm so wie hier nur ein Teil aller bits überhaupt an der Ergebnisfindung teilnimmt (einfach alle Masken ver-or-en), könnte man den Rest vergessen und aus einem 64bittigen Problem z.B. wie hier ein 12bittiges machen. Klein genug für eine lookup-table.
-
camper schrieb:
Der Ansatz ist vielleicht trotzdem nicht so doof. Jedenfalls die Faltung könnte brauchbar sein:
Wenn im echten Programm so wie hier nur ein Teil aller bits überhaupt an der Ergebnisfindung teilnimmt (einfach alle Masken ver-or-en), könnte man den Rest vergessen und aus einem 64bittigen Problem z.B. wie hier ein 12bittiges machen. Klein genug für eine lookup-table.Alle diese Konstanten bestehen aus genau drei gesetzten Bits. Das mit der lookup-Tabelle habe ich aber nicht so ganz verstanden
-
Franz von und zu Assisi schrieb:
Alle diese Konstanten bestehen aus genau drei gesetzten Bits. Das mit der lookup-Tabelle habe ich aber nicht so ganz verstanden
Wie viele Bits sind gesetzt, wenn alle Konstanten or-verknüpft werden?
-
camper schrieb:
Wie viele Bits sind gesetzt, wenn alle Konstanten or-verknüpft werden?
Das kann man so nicht ohne weiteres sagen, das hängt von den einzelnen Cases der Switch-Anweisung ab. Ich weiß jetzt nicht genau auf was du hinaus willst, ich poste einfach mal den ersten Teil meiner Funktion:
Boolean SpielBeenden1(void) { const __int64 x = ~Feld1; switch(Hoehe[3]) { case 0: if(!(x & 0x20820000000i64 && x & 0x820020000i64 && x & 0x20020800i64 && x & 0x20820i64 && x & 0x10204i64 && x & 0x4210000000i64)) return true; break; case 1: if(!(x & 0x20008100i64 && x & 0x10410i64 && x & 0x10410000000i64 && x & 0x2108000000i64 && x & 0x108020000i64 && x & 0x10010400i64 && x & 0x8102i64 && x & 0x410010000i64)) return true; break; case 2: if(!(x & 0x810004000i64 && x & 0x4010800i64 && x & 0x8208000000i64 && x & 0x208008000i64 && x & 0x8008200i64 && x & 0x8208i64 && x & 0x84010000i64 && x & 0x10004080i64 && x & 0x4081i64 && x & 0x1084000000i64)) return true; break; case 3: . . . . . case 5: if(!(x & 0x380000i64 && x & 0x8102000000i64 && x & 0x2108i64 && x & 0x1041000000i64 && x & 0x41001000i64 && x & 0x1001040i64 && x & 0x1041i64)) return true; break; default: break; } switch(Hoehe[4]) { . . . . }
-
Darf man fragen wie das Spiel heißt?
-
Der Fluch der Mumie...