JIT and notes for 2024/kurdyukov3

This commit is contained in:
Ilya Kurdyukov authored and GitHub committed 2025-08-03 21:36:13 +07:00
1 parent 4c896b8965
commit 708a2e4795
2 files changed
+683 -1

No files matched your search

+12 -1
View File
@@ -215,7 +215,7 @@ Use:
``` <!---sh-->
./prog lzmadec.bin < sdk.zip.lzma > sdk.zip
``` <!---sh-->
```
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).
<!--
+671
View File
@@ -0,0 +1,671 @@
#ifndef JIT
#if defined(__x86_64__) || defined(__i386__) || \
defined(__e2k__) || defined(__aarch64__)
#define JIT 1
#else
#define JIT 0
#endif
#endif
#ifndef DUMP
#define DUMP 0
#endif
#ifdef _WIN32
#include <fcntl.h>
#define U(a,b) b
#else
#define U(a,b) a
#define _GNU_SOURCE
#include <unistd.h>
#if JIT
#include <sys/mman.h>
#endif
#endif
#ifdef SDL
#include <SDL.h>
#if SDL_MAJOR_VERSION < 2
#define V(a,b) a
#else
#define V(a,b) b
#endif
#define L(a,b) a
#else
#define L(a,b) b
#ifdef _WIN32
#include <windows.h>
#define Q(x) (QueryPerformance##x(&q),q.QuadPart)
#else
#include <sys/time.h>
#include <X11/Xlib.h>
#ifdef TERMIOS
#define T(a,b) a
#include <termios.h>
#include <sys/ioctl.h>
#else
#define T(a,b) b
#include <X11/Xutil.h>
#endif
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#define H x->h[c&7]
typedef struct{
#if JIT
char**b,*i,*q,*p;
#endif
unsigned*m,k,y,z; char s[33]; void*h[8];
L(SDL_Surface*S V(; ,; SDL_Window*W; ),
U(Display*D; T(struct termios t[2]; char I[64],
Window W; GC G; XImage*I; Atom A),
HWND W; HDC D; double f);)
} ctx_t
U(; ,; static int E=0;
static LRESULT CALLBACK P(HWND a,UINT b,WPARAM c,LPARAM d){
E|=b==2; ; return DefWindowProcA(a,b,c,d); } )
static int sys(unsigned n,int c,unsigned b,ctx_t*x){
void*f; unsigned a,d;
L(SDL_Event E,U(struct timeval t,LARGE_INTEGER q; MSG M));
switch(n) {
case 1:b=H?c<0?fgetc(H):fputc(b,H):-1; break;
case 2:L(b=SDL_GetTicks(),U(gettimeofday(&t,0); b=t.tv_sec*1000+t.tv_usec/1000,b=Q(Counter)*x->f)); break;
case 3:L(SDL_Delay(b),U(t.tv_sec=0; t.tv_usec=b*1000; select(0,0,0,0,&t),Sleep(b))); break;
case 4:x->s[c&31]=b&&b-48>9&&(b|32)-97>25&&b-46?95:b; break;
case 5:b=!(H=H?fclose(H),f=0:fopen(x->s,b?"wb":"rb")); break;
case 6:b=H?c<0?ftell(H):fseek(H,(int)b,c/8):-1; break;
case 7:
#define B(i,a,j) if(c==i){ x->m[1]=E.a.x|E.a.y<<14|E.a.j<<28; b
#ifdef DUMMY
fprintf(stderr,"!!! dummy\n"); b=6; break;
case 8: b=2; break;
case 9:
#elif defined SDL
if(!(x->S||~(-c&-b)>>12)){
SDL_Init(SDL_INIT_VIDEO);
V(x->S=SDL_SetVideoMode(x->y=c,x->z=b,32,SDL_SWSURFACE);SDL_WM_SetCaption(x->s,0),
n=SDL_WINDOWPOS_UNDEFINED;
x->S=SDL_GetWindowSurface(x->W=SDL_CreateWindow(x->s,n,n,x->y=c,x->z=b,0)));
}
b=x->S?V(12,16)+(x->S->format->Rmask*513>>24&3):0; break;
case 8:
while(b=2,x->S&&SDL_PollEvent(&E)){
c=E.type; b=c==SDL_KEYUP;
if(b||c==SDL_KEYDOWN){ x->m[1]=E.key.keysym.sym; break; }
b=c==SDL_MOUSEBUTTONUP; B(SDL_MOUSEBUTTONDOWN||b,button,button)+=4; break; }
B(SDL_MOUSEMOTION,motion,x)=6; break; }
if(c==SDL_QUIT){ b=3; break; }
}
break;
case 9:b&=x->k; if(x->S&&b+x->y*x->z<x->k){
for(n=0; n<x->z; n++)memcpy((char*)x->S->pixels+n*x->S->pitch,x->m+b+n*x->y,x->y*4);
V(SDL_Flip(x->S),SDL_UpdateWindowSurface(x->W));
}
#elif defined(_WIN32)
if(!(x->W||~(-c&-b)>>12)){
WNDCLASSA C={ 0,P,0,0,0,0,0,0,0,x->s} ;
RECT r={ 0,0,x->y=c,x->z=b} ; RegisterClassA(&C); n=1<<31;
AdjustWindowRect(&r,c=WS_CAPTION|WS_SYSMENU|WS_VISIBLE,0);
x->D=GetDC(x->W=CreateWindowExA(0,x->s,x->s,c,n,n,
r.right-r.left,r.bottom-r.top,0,0,0,0));
}
b=x->W?10:0; break;
case 8:b=E*3;
if(!b)while(b=2,x->W&&PeekMessageA(&M,x->W,0,0,1)){
b=M.message-512; if(b<11){ x->m[1]=M.lParam+(M.wParam&(b>9)<<30); b+=9; break; }
b=(b|4)+252; if(b<2){ x->m[1]=M.wParam; break; }
DispatchMessageA(&M);
}
break;
case 9:b&=x->k; if(x->W&&b+x->y*x->z<x->k){
int B[10]={ 40,x->y,-x->z,1<<21|1};
SetDIBitsToDevice(x->D,0,0,x->y,x->z,0,0,0,x->z,x->m+b,f=&B,0);
SwapBuffers(x->D);
}
#elif defined(TERMIOS)
if(!(x->y|~(-c&-b)>>12)){
x->D=XOpenDisplay(0);
tcgetattr(0,x->t); x->t[1]=*x->t; x->t->c_lflag&=~ICANON&~ECHO;
x->t->c_cc[VMIN]=x->t->c_cc[VTIME]=0; tcsetattr(0,TCSANOW,x->t);
x->y=c; x->z=b;
printf("\33[?25l\33[2J");
}
b=x->D?4:0; break;
case 8:
{ static int i,n;
while(read(0,&b,1)>0);
if(!(i&=255))XQueryKeymap(x->D,&x->I[n^=32]);
for(b=2;i<256;i++)if((x->I[i>>3]^x->I[i>>3|32])&(a=1<<(i&7))){
x->m[1]=XKeycodeToKeysym(x->D,i,0); b=!(x->I[n|i++>>3]&a);
break;
} }
break;
case 9:b&=x->k; if(b+x->y*x->z<x->k){
unsigned char*p,*r,*g;
struct winsize s;
int W,Q,w=x->y,h=x->z,q,e,i,j;
ioctl(0,TIOCGWINSZ,&s);
W=s.ws_col; Q=s.ws_row*2;
p=malloc(W*Q*3);
e=w*Q<W*h?q=(w*Q+h/2)/h,Q:(q=W,(h*W+w/2)/w);
r=f=x->m+b;
{
int x,y,u,v,a,b,c,k,l,z=16,Y,Z;
for(v=y=0; y<Q; v=c){ c=++y*z*h/e;
for(u=x=0; x<W; u=a){ a=++x*z*w/q;
for(j=0; j<3; p[(y*q+x-q)*3-3+j++]=(l+b/2)/b){ l=0;
for(i=v; Z=((i^c)<z?c%z:z)-i%z,i<c; i+=Z)
for(k=u; Y=((k^a)<z?a%z:z)-k%z,k<a; k+=Y)
l+=r[i/z*w*4+k/z*4+j]*Y*Z;
b=a-u; b*=c-v; } } }
}
for(j=0;j<e;j+=2){
printf("\33[%dH",j/2+1);
for(i=0;i<q;i++){
r=p+(j*q+i)*3,g=r+q*3;
printf("\33[");
if(j+1<e)printf("48;2;%d;%d;%d",*g,g[1],g[2]);
printf("m\33[38;2;%d;%d;%dm\342\226\200",*r,r[1],r[2]);
}
printf("\33[m%*s",W-q,"");
}
free(p);
printf(j<Q?"\n\33[J":"\33[F\n");
}
#else
if(!(x->I||~(-c&-b)>>12)){
XSizeHints h; h.flags=PMinSize|PMaxSize;
h.min_width=h.max_width=c; h.min_height=h.max_height=b;
x->G=XDefaultGC(x->D=XOpenDisplay(0),0);
x->W=XCreateSimpleWindow(x->D,RootWindow(x->D,0),0,0,c,b,1,0,0);
XSelectInput(x->D,x->W,KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask);
XSetStandardProperties(x->D,x->W,x->s,0,0,0,0,&h);
x->A=XInternAtom(x->D,"WM_DELETE_WINDOW",0); XSetWMProtocols(x->D,x->W,&x->A,1);
XMapWindow(x->D,x->W);
x->I=XCreateImage(x->D,DefaultVisual(x->D,0),24,ZPixmap,0,0,x->y=c,x->z=b,32,0);
}
b=x->I?6:0; break;
case 8:
while(b=2,x->I&&XPending(x->D)){
XEvent E; XNextEvent(x->D,&E); c=E.type;
if(c-ClientMessage||*E.xclient.data.l-x->A) {
b=c==KeyRelease; if(b||c==KeyPress){ x->m[1]=XLookupKeysym(&E.xkey,0); break; }
b=c==ButtonRelease; B(ButtonPress||b,xbutton,button)+=4; break; }
B(MotionNotify,xmotion,x)=6; break; }
} else { b=3; break; }
}
break;
case 9:b&=x->k; if(x->I&&b+x->y*x->z<x->k){
x->I->data=f=x->m+b; XPutImage(x->D,x->W,x->G,x->I,0,0,0,0,x->y,x->z); XSync(x->D,0);
}
#endif
break;
case 10:if(b){
#if JIT
x->p=x->q; d=x->k/4; for(a=0; a<=d; a++)x->b[a]=x->i;
#endif
} U(; ,else b=H?_setmode(_fileno(H),O_BINARY):0; )
break;
default:L(; ,U(
T(x->D?(tcsetattr(0,TCSANOW,x->t+1),printf("\33[?25h")):0,
x->I?x->I->data=0:0); ,; ))
d=(*x->m-4)&x->k; a=x->m[d]>>14;
if(a)fprintf(stderr,"bad opcode at 0x%x: 0x%x\n",d*4,x->m[d]);
//else fprintf(stderr,"exit code: %d (0x%08x)\n",c,c);
#if JIT && DUMP == 2
if((f=fopen("codedump.bin","wb"))){
char*p=x->p,*p0=(char*)(x->b+x->k/4+1);
fwrite(p0,1,p-p0,f); fclose(f);
}
#endif
exit(a?1:c);
}
return b;
}
#ifdef __e2k__
#define E2K_WAIT(flags) __asm__ ("wait " flags : : : "memory")
#define __clear_cache __clear_cache_e2k
static void __clear_cache_e2k(void *begin, void *end) {
unsigned long step = 256, ptr = (long)begin & -step;
E2K_WAIT("st_c=1");
for (; ptr < (unsigned long)end; ptr += step)
__builtin_storemas_64u(0, (void*)ptr, 15, __LCC_CHAN_ANY);
E2K_WAIT("fl_c=1");
}
#endif
int main(int c,char**x){
void*f=c-->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<<b%4*8;
fclose(f); m[1]=b; C.m=m; C.k=k; C.h[0]=stdin; C.h[1]=stdout; C.h[2]=stderr;
#ifdef _WIN32
{ LARGE_INTEGER q; C.f=1000.0/Q(Frequency); timeBeginPeriod(1); }
#endif
#if JIT
n=(k/4+3)*sizeof(f)+An;
A=U(mmap(0,n,PROT_EXEC+PROT_READ+PROT_WRITE,MAP_PRIVATE+MAP_ANONYMOUS,-1,0),
VirtualAlloc(0,n,MEM_COMMIT,PAGE_EXECUTE_READWRITE));
if(!A)return 1;
*A++=(void*)(size_t)sys; *A++=f=&C; p=p0=f=A+k/4+1;
#ifdef __aarch64__
P=f=p;
*P++=0xa9bc7bf9; // stp x25, x30, [sp, #-64]!
*P++=0xa90163f7; // stp x23, x24, [sp, #16]
*P++=0xa9025bf5; // stp x21, x22, [sp, #32]
*P++=0xa90353f3; // stp x19, x20, [sp, #48]
*P++=0xaa0003f3; // mov x19, x0
*P++=0xaa0103f4; // mov x20, x1
*P++=0xa97f5a95; // ldp x21, x22, [x20, #-16]
a=k*4+3;
*P++=0xd2800017|(a&65535)<<5; // mov x23, #<lo>
*P++=0xf2a00017|(a>>16)<<5; // movk x23, #<hi>, 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, #<lo>
P[-1]=0xf2a00000|(a>>16)<<5; // movk x0, #<hi>, 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<<h)){ \
*P++=0x52800000|i|(b&65535)<<5; /* mov */ \
if(b>>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(<<c)d++; if(c)W(>>(32-c))} else *m+=b?d:0;
#endif
}
}
return 1;
}