From 708a2e47956afd5c30e3235509778c79f8ae33a7 Mon Sep 17 00:00:00 2001 From: Ilya Kurdyukov <59548320+ilyakurdyukov@users.noreply.github.com> Date: Sun, 3 Aug 2025 21:36:13 +0700 Subject: [PATCH] JIT and notes for 2024/kurdyukov3 --- 2024/kurdyukov3/README.md | 13 +- 2024/kurdyukov3/prog.jit.c | 671 +++++++++++++++++++++++++++++++++++++ 2 files changed, 683 insertions(+), 1 deletion(-) create mode 100644 2024/kurdyukov3/prog.jit.c diff --git a/2024/kurdyukov3/README.md b/2024/kurdyukov3/README.md index 93c434448..3c6d652ac 100644 --- a/2024/kurdyukov3/README.md +++ b/2024/kurdyukov3/README.md @@ -215,7 +215,7 @@ Use: ``` ./prog lzmadec.bin < sdk.zip.lzma > sdk.zip -``` +``` to decompress the SDK (.zip archive is without compression). @@ -271,6 +271,17 @@ the `*.bin` files may be produced via this `make samples` rule: ### Web version I also wrote a web version in javascript. It is in `ogvm.html`, start a local server with `$ python3 -m http.server 8000` and open `http://127.0.0.1:8000/ogvm.html` in your browser. +Files can be dragged into the window or read from the current directory. + + +### JIT version + +An extended version with a fast JIT compiler (`prog.jit.c`) is also included. Supported architectures for JIT: x86/x86_64/aarch64/e2k. This version can also output graphics to a terminal window when using the `-DTERMIOS` option. For SDL use `-DSDL`. + + +### Extra notes + +This entry was written in September 2020 in one month, later only a bonus JIT was made. The patch for Doom was later used in the [FPDoom](https://github.com/ilyakurdyukov/fpdoom) project (a port of Doom for feature phones). 1?fopen(x[1],"rb"):0; + unsigned a,b=0,d,n=0,k=(1<<24)-1,*m=calloc(k+32,4); + ctx_t C={ 0} ; +#if JIT +#ifdef __x86_64__ +#define S(a,b) a +#define F E +#elif defined(__i386__) +#define S(a,b) b +#define F(x) +#elif defined(__e2k__) + long*P; +#elif defined(__aarch64__) + int*P; +#else +#error +#endif + char**A,*p,*p0,*pr; int An=1<<24; /* 1<<30 max for e2k */ +#if DUMP == 1 + FILE*ff=fopen("codedump.bin","wb"); +#endif +#endif + if(m&&f){ for(m+=16; b<=k&&((a=fgetc(f))<256||(a=x[c][n++]&255)||(n=0,--c)); b++)m[b/4]|=a< + *P++=0xf2a00017|(a>>16)<<5; // movk x23, #, lsl #16 + *P++=0x927ceef8; // and x24, x23, #-16 + *P++=0xd341ff18; // lsr x24, x24, #1 + *P++=0x100000d9; // adr x25, #6 + *P++=0xb9400260; // ldr w0, [x19] + *P++=0x8a000700; // and x0, x24, x0, lsl #1 + *P++=0xf8606a80; // ldr x0, [x20, x0] + *P++=0xd61f0000; // br x0 + C.b=A; C.i=f=P; + *P++=0xd2800000; // mov x0, #0 + *P++=0xa94353f3; // ldp x19, x20, [sp, #48] + *P++=0xa9425bf5; // ldp x21, x22, [sp, #32] + *P++=0xa94163f7; // ldp x23, x24, [sp, #16] + *P++=0xa8c47bf9; // ldp x25, x30, [sp], #64 + *P++=0xd65f03c0; // ret + __clear_cache(p0, P); +#if DUMP == 1 + fwrite(p0,1,(char*)P-p0,ff); fflush(ff); +#endif + C.q=f=P; sys(10,0,-1,&C); + for(; ; ){ + unsigned i,x,r,q,X,t,h; + pr=((char*(*)(void*,void*))(size_t)p0)(m,A); + if(pr){ P=f=pr; d=(*m=*P)&k; p=A[d/4]; + if(p==C.i&&C.p==pr+8)C.p-=16; + else{ + pr=p-C.i?p:C.p; + c=(int*)pr-P+2; + if((c^c>>31)>>25){ + a=((p-C.i?p:C.p)-C.i-4)>>2; + P[-2]=0xd2800000|(a&65535)<<5; // mov x0, # + P[-1]=0xf2a00000|(a>>16)<<5; // movk x0, #, lsl #16 + *P=0x8b000b20; // add x0, x25, x0, lsl #2 + P[1]=0xd61f0000; // br x0 + } else P[-2]=0x14000000|(c&0x3ffffff); // b (An=1<<27 max) + __clear_cache(P-2,P+2); + if(p-C.i)continue; + } + } + if(C.p>p0+An-128)sys(10,0,-1,&C); + P=f=C.p; + a=m[d=*m&k]; X=d+4; A[d/4]=f=P; + if(a==1<<28&&m[d+1]+m[d+2])X+=m[d+3],x=0; + else{ + n=a>>23; c=q=0; + r=n-64<64?c=256<<(~n/4&8),q=c>>n/16%2,n<96:2; + i=m[d+2]||n-32>95||(n&12); do{ + x=a&127; a>>=7; b=m[++d]; + if(x>1)b*=4; if(x)b&=k*4+3; + if(x-1<2&&!b)x=0,b=X; + if(!x){ + b=((b+q)|-c)+q; h=0x12800000; // movn + t=~b>>16&&~b<<16?h|=1<<30,b:~b; // mov + if(!t||t<<16)*P++=h|i|(t&65535)<<5,h|=1<<29; + if(t>>16)*P++=1<<21|h|i|(t>>16)<<5; // mov{k|z}, #{t>>16}, lsl #16 + } else{ +#define R(i) \ + h=x>2?2:r; \ + t=0x39400260|(b>>h)<<10; \ + if(b&~(4095<>16)*P++=0x72a00000|i|(b>>16)<<5; /* movk */ \ + t=0x38606a60|i<<16; /* ldrb w{i}, [x19, x{i}] */ \ + } \ + if(x>2){ \ + *P++=t|2<<30|i; \ + b=x-65; /* {sub|add} x{i+4}, x19, #{b} */ \ + if(b)*P++=0x91000264|(b>>31)<<30|i|(b>>31?-b:b)<<10; \ + *P++=0x0a170000|i*33; /* and w{i}, w{i}, w23 */ \ + t=0x38606800|i<<16|(b?i+4:19)<<5; \ + } + R(i) + *P++=t|r<<30|(c!=q)<<23|i; // ldr[s][h|b] w{i}, [x19, x{i}] + } + } while(i++&1); + + c=0; r=0; + if(i-3)a>>=7,++d; + else if(n-32<96)switch((q=n&15)){ + case 5:*P++=0x1b027c20; break; /* mul */ + case 6:case 7:*P++=0x1ac20820|(n&16)<<6; /* div{u|s} */ + if(n&1)*P++=0x1b028400; /* msub w0, w0, w2, w1 */ + break; + case 8:P-=!x,*P++=x?0x1ac22020: /* lsl */ + 0x53007c20^(b&31)<<10^(-b&31)<<16; break; + case 9:P-=!x,*P++=x?0x1ac22420+((n&16)<<6): /* {l|a}sr */ + 0x53007c20^(n&16)<<26^(b&31)<<16; break; + case 0:case 1: + if(!x&&!(b>>12&&-b>>12)){ + if(b>>31)b=-b,q^=1; + P[-1]=0x11000020|q<<30|b<<10; /* {add|sub} w0, w1, #{b} */ + break; + } + case 2:case 3:case 4: + *P++=0x020020|(0x0a4a2a4b0b>>q*8&255)<<24; break; + default: c=1; + if(x||(b>>12&&-b>>12))*P++=0x6b02003f; /* cmp w1, w2 */ + else P[-1]=b>>31?0x3100003f|-b<<10:0x7100003f|b<<10; /* cm{p|n} w1, #{b} */ + r=(n&16?0xbdca01:0x398201)>>(q-10)*4&15; + *P++=0x1a9f07e0|r<<12; // cset w0, {r} + } else{ + *P++=n>31||(!n&&a)?0x12800000:0x52800000|n<<5; // w0 = -1 or n + if(n-1>9){ + *P++=0x52800004|(X&65535)<<5; // mov w4, {x.lo} + if(X>>16)*P++=0x72a00004|(X>>16)<<5; // movk w4, {x.hi} + *P++=0xb9000264; // str w4, [x19] + } + *P++=0xaa1603e3; // mov x3, x22 + *P++=0xd63f02a0; // blr x21 + } + + b=m[d+1]; x=a&127; + if(x){ + n=a>>7&3; // 0123 -> 4321 + r=0x12>>n*2&3; + if(x>1)b*=4; if(x)b&=k*4+3; + if(x>2||b){ + R(1) + *P++=t^1<<22^r<<30; // str[h|b] w0, [x19, x1] + } else{ + // dynamic jump + *P++=0xb9000260; // str w0, [x19] + *P++=0x8a000700; // and x0, x24, x0, lsl #1 + *P++=0xf8606a80; // ldr x0, [x20, x0] + *P++=0xd61f0000; // br x0 + x=-1; + } + } else if(b){ // jump if neq + // b.{!r} or cbz w0, #5 + P-=c,*P++=c?0x540000a0|r:0x340000a0; + *P++=0x10000040; // adr x0, #2 + *P++=0xd61f0320; // br x25 + *P++=X+b; *P++=0; + } + } + if(~x){ + *P++=0x10000040; // adr x0, #2 + *P++=0xd61f0320; // br x25 + *P++=X; *P++=0; + } + p=f=P; + __clear_cache(C.p, p); +#elif defined(__e2k__) +#define NOP 128 +#define E4(x) *P++=(long)(x)<<32; + P=f=p; + *P++=0x58ecda86bc108056|NOP*2; + *P++=0x6781d18211c0db84; + *P++=0x6781d5836680c085; + *P++=0x01c00000040000c4; + *P++=k*4+3-(1L<<37); + *P++=0x0118fff8fff0; + + *P++=0x0185d88520000011; E4(k&-4) + *P++=0x1985c18520000001; + *P++=0x6781858520000001|NOP*3; + *P++=0x8000000004001012|NOP*7; *P++=0xe1c085d1; + *P++=0; + *P++=0xc000042000001001; + C.b=A; C.i=f=P; + *P++=0x11c0c00004000001; + *P++=0x8000000020005013|NOP*5; *P++=0xf00000001100c080; + *P++=0xc0000c2000001001; + __clear_cache(p0, P); +#if DUMP == 1 + fwrite(p0, 1, (char*)P-p0, ff); fflush(ff); +#endif + C.q=f=P; sys(10,0,-1,&C); + for(; ; ){ + unsigned i,x,r,q,X,t; + long pr=((long(*)(void*,void*))(size_t)p0)(m,A); + if(pr){ d=(*m=pr)&k; p=A[d/4]; b=pr>>32; f=(char*)A+b; + if(p==C.i&&C.p==(char*)f+8)C.p-=24; + else{ *((int*)f-1)=((long*)(p-C.i?p:C.p)-(long*)f+2)&~0U>>4; __clear_cache((int*)f-1,f); + if(p-C.i)continue; } + } + if(C.p>p0+An-256)sys(10,0,-1,&C); + P=f=C.p; + a=m[d=*m&k]; X=d+4; A[d/4]=f=P; + if(a==1<<28&&m[d+1]+m[d+2])X+=m[d+3],x=0; + else{ + n=a>>23; c=q=0; + r=n-64<64?c=256<<(~n/4&8),q=c>>n/16%2,n<96:2; + i=m[d+2]||n-32>95||(n&12); do{ + x=a&127; a>>=7; b=m[++d]; + if(x>1)b*=4; if(x)b&=k*4+3; + if((x-1)<2&&!b)x=0,b=X; + if(!x){ + b=((b+q)|-c)+q; t=(n&16)<<20; + if(b>~32U)*P++=0x0ac0c00004000001|(long)(t|~b<<16|i)<<32; + else if(b>>5)*P++=0x10c0d80004000011|(long)(t|i)<<32,E4(b) + else*P++=0x10c0c00004000001|(long)(t|b<<16|i)<<32; + } else{ + if(b>>5)*P++=0x6480d80004000011|NOP*2|(long)((x>2?2:r)<<24|i)<<32,E4(b) + else*P++=0x64c0800004000001|NOP*2|(long)((x>2?2:r)<<24|b<<16|i)<<32; + if(x>2){ + b=x-65; if(b){ + *P++=0x1180d8040c000012|(long)i<<32; + *P++=0x01008400|i<<16|i|(long)b<<32; + } else*P++=0x0100840004000001|(long)(i<<16|i)<<32; + *P++=0x6400000004000001|NOP*2|((b?i+4:128)<<16|r<<24|i*257L)<<32; + } + if(c-q||(i<2&&n==23))*P++=0x0cc0000020000001|(r<<16|i*257L)<<32; + } + } while(i++&1); + + c=0; r=1; + if(i-3)a>>=7,++d; + else if(n-32<96)switch((q=n&15)){ +#if __iset__ < 5 + case 5:*P++=0x2001020020800011|NOP*5; *P++=7<<22; break; +#else + case 5:*P++=0x2601020041000011|NOP*3; *P++=7<<22; break; +#endif + case 6:*P++=0x4001020080000001|NOP*7|(n&16L)<<53; *P++=NOP*2; break; + case 7:*P++=0x4501020080000001|NOP*7|(n&16L)<<53; *P++=NOP*2; break; + default: + if(q>9){ c=1; + *P++=0x2001020004000001|NOP|((n&16?0xceec44:0x266244)>>(q-=10)*4&15L)<<36; + *P++=0x0ec0c10004010011|NOP; r=0x32>>q&1; *P++=(r*8|0x846L)<<52; + } else*P++=0x0001020004000001|((0xdcfff04298>>q*4&15L)+(q==9&&(n&16)))<<57; + } else{ + if(n>31||(!n&&a))n=-1; + if(n-1>9){ *P++=0x10c0d88504000011,E4(X)*P++=0x2680c08510000001; } + *P++=0x8000000004001012|NOP*7; *P++=0xe1c082d1; + *P++=0x11c083030c000012; *P++=0x10c0d800|(long)n<<32; + *P++=0xc000042000009012; *P++=0x50000004; + } + + b=m[d+1]; x=a&127; + if(x){ + n=a>>7&3; // 0123 -> 4321 + q=0x12>>n*2&3; + if(x>2){ + b=(b&k)*4; + if(b>>5)*P++=0x6680d88504000011|NOP*2,E4(b) + else*P++=0x66c0808504000001|NOP*2|(long)b<<48; + b=x-65; if(b){ + *P++=0x1180d8860c000012; + *P++=0x01858485|(long)b<<32; + } else*P++=0x0185848504000001; + *P++=0x2480850010000001|(b?6L:0L)<<48|(long)q<<56; + } else{ + b=(x-1?b*4:b)&(k*4+3); + if(b>>5)*P++=0x2480d80010000011|(long)q<<56,E4(b) + else if(b)*P++=0x24c0800010000001|(long)q<<56|(long)b<<48; + else{ + *P++=0x0100d88514000012; + *P++=0x2680c000|(k&-4L)<<32; + *P++=0x1985c18520000001; + *P++=0x6781858520000001|NOP*3; + *P++=0x8000000004001012|NOP*7; *P++=0xe1c085d1; + *P++=0; + *P++=0xc000042000001001; + x=-1; + } + } + } else if(b){ + if(c)P-=2; else*P++=0x2000c04004000001|NOP*2; + *P++=0xc000004004005023|(long)r<<37; + *P=0x11c0dc00|(((long*)C.i-P+2)&0xfffffffL)<<32; P++; + *P=(long)(X+b)<<32|((char*)P-(char*)A); P++; + } + } + if(~x){ + *P++=0xc000002004005023; + *P=0x11c0dc00|(((long*)C.i-P+2)&0xfffffffL)<<32; P++; + *P=(long)X<<32|((char*)P-(char*)A); P++; + } + p=f=P; + __clear_cache(C.p, p); +#else /* x86 */ +#define E(x) *p++=(char)(0x##x); +#define E4(x) *(int*)p=x; p+=4; + E(55)E(53)F(41)E(56) + S(E(48)E(89)U(E(fb),E(cb))E(49)E(89)U(E(f6),E(d6)), + E(8b)E(5c)E(24)E(10)E(8b)E(74)E(24)E(14)) + E(bd)E4(k*4+3) + E(8b)E(03) + E(25)E4(k&-4) + F(41)E(ff)E(24)S(E(46),E(06)) + C.b=A; C.i=p; + E(6a)E(00) + E(58)F(41)E(5e)E(5b)E(5d)E(c3) + C.q=p; sys(10,0,-1,&C); + for(; ; ){ + unsigned i,x,r,q,X; + pr=((void*(*)(void*,void*))(size_t)p0)(m,A); + if(pr){ d=(*m=*(int*)pr)&k; pr[-5]=-23; p=A[d/4]; // *(int*)pr=0; + if(p!=C.i){ *(int*)(pr-4)=p-pr; continue; } *(int*)(pr-4)=C.p-pr; C.p-=C.p-pr-4?0:9; } + if(C.p>p0+An-256)sys(10,0,-1,&C); + p=C.p; +#define ER if(b>>7){ E(83+i*8)E4(b)} else{ E(43+i*8)E(0+b)} + a=m[d=*m&k]; X=d+4; A[d/4]=p; + if(a==1<<28&&m[d+1]+m[d+2])X+=m[d+3],x=0; + else{ + n=a>>23; r=c=q=0; + if(n-64<64)r=(n/2&8)+46-n/32,c=256<<(~n/4&8),q=c>>n/16%2; + for(i=0; i<2; i++){ + x=a&127; a>>=7; b=m[++d]; + switch(x){ + case 0:E(b8+i)E4(b=((b+q)|-c)+q)break; + case 1:case 2: + b=(x-1?b*4:b)&(k*4+3); + if(b){ if(r)E(f)E(8b+r)ER } + else{ E(b8+i)E4(X)} break; + default: + b=(b&k)*4; E(8b)ER + E(21)E(e8+i)b=x-65; + if(r)E(f)E(8b+r)E(04+!!b*64+i*8)E(03+i*8)if(b)E(0+b) + } + } + + c=n>31&&n%16>9; r=0; + if(n-32<96)switch(n&15){ + case 5:E(0f)E(af)E(c1)break; + case 6:case 7:if(n&16){ E(99)E(f7)E(f9)} + else{ E(33)E(d2)E(f7)E(f1)} r=n&1; break; + case 8:E(d3)E(e0)break; + case 9:E(d3)E(e8+(n&16))break; + default:q=(n%16<5?0x46150>>n%8*4&7:7)*8; + if(x){ E(03+q)E(c1)} else if(b||n%16>3){ + if(b-(char)b)p[-5]=5+q; else{ p-=5;E(83)E(c0+q)E(0+b)} + } else p-=n=5; break; + } else{ + if(n>31||(!n&&a))n=-1; + if(n-1>9){ E(c7)E(03)E4(X)} + S(E(89)U(E(ca)E(89)E(c6)E(bf),E(c2)E(49)E(89)E(c8)E(b9)) + E4(n)U(E(49),E(4d))E(8b)E(4e)E(f8)E(41), + E(ff)E(76)E(fc)E(51)E(50)E(6a)E(0+n)) + E(ff)E(56)S(E(f0),E(f8)E(83)E(c4)E(10)) + } + + q=c?(n&16?0x45cefd:0x452673)>>~n%8*4&15:5; + b=m[d+1]; x=a&127; + if(x){ + n=a>>7&3; + if(c){ E(0f)E(90+q)E(c0)if(n<3){ E(0f)E(b6)E(c0)} } + if(x>2){ + E(8b)b=(b&k)*4; i=1; ER + E(21)E(e9) + } + if(n==2)E(66)E(89-n%2) + if(x<3){ b=x-1?(b&k)*4:b&(k*4+3); + if(b>>7){ E(83+r*16)E4(b)} else{ + E(43+r*16)E(0+b) + if(!b){ if(r)E(90+d*2)E(25)E4(k&-4)F(41)E(ff)E(24)S(E(46),E(06)) x=-1; } + } + } else{ b=x-65; E(04+!!b*64+r*16)E(0b)if(b)E(0+b) } + } else if(b){ + if(n<32||n%16-5<3){ E(85)E(c0+r*18)} + E(71^q)E(9)E(e8)E4(C.i-p-2)E4(X+b) + } + } + if(x+1){ E(e8)E4(C.i-p-2)E4(X)} +#endif +#if DUMP == 1 + fwrite(C.p,1,p-C.p,ff); fflush(ff); +#endif + C.p=p; +#else + for(; ; ){ +#define R b=m[++d]; n=a&127; if(n){ if(n-1)b=m[b&k]+(n>2?n-65:0); \ + if(n-2){ n=b%4*8; b=b/4&k; b=m[b]>>n|m[b+1]*2<<~n%32; } } a>>=7; + a=m[d=*m&k]; *m+=4; R c=b; R d=m[d+1]; n=a>>9; + switch(n){ +#define X(n,t,o) case n:b=(t)c o(t)b; break; +#define Y(n,t,a,b,c,d)X(n,t,a)X(n+1,t,b)X(n+2,t,c)X(n+3,t,d) +#define O(n,t) Y(n,t,+,-,|,^)Y(n+4,t,&,*,/,%)Y(n+8,t,<<,>>,==,!=)Y(n+12,t,<,<=,>,>=) + default:b=sys(n,c,b,&C); break; + O(32,unsigned)O(48,int) + O(64,unsigned short)O(80,short) + O(96,unsigned char)O(112,signed char) + } + n=a&127; if(n){ c=0; d=n>2?m[d&k]+n-65:d; + d=(n-2?c=d%4*8,d/4:d)&k; n=-1; n>>=a>>4&24; +#define W(c) m[d]=(m[d]|n c)^(~b&n)c; + W(<>(32-c))} else *m+=b?d:0; +#endif + } + } + return 1; +} +