2 when I say JIT, I mean load time, not execution time.
\r
5 qc jump offsets are all constants. we have no variable offset jumps (other than function calls/returns)
\r
6 field remapping... fields are in place, and cannot be adjusted. if a field is not set to 0, its assumed to be a constant.
\r
9 none at the moment...
\r
10 instructions need to be chained. stuff that writes to C should be cacheable, etc. maybe we don't even need to do the write to C
\r
11 it should also be possible to fold in eq+ifnot, so none of this silly storeing of floats in equality tests
\r
14 ebx - prinst->edicttable
\r
18 edi - tmp (because its preserved by subfunctions
\r
21 to use gas to provide binary opcodes:
\r
22 vim -N blob.s && as blob.s && objdump.exe -d a.out
\r
26 #include "progsint.h"
\r
30 static float ta, tb, nullfloat=0;
\r
32 unsigned int *statementjumps; //[MAX_STATEMENTS*2]
\r
33 unsigned char **statementoffsets; //[MAX_STATEMENTS]
\r
34 unsigned int numjumps;
\r
35 unsigned char *code;
\r
36 unsigned int codesize;
\r
37 unsigned int jitstatements;
\r
39 void EmitByte(unsigned char byte)
\r
41 code[codesize++] = byte;
\r
43 void Emit4Byte(unsigned int value)
\r
45 code[codesize++] = (value>> 0)&0xff;
\r
46 code[codesize++] = (value>> 8)&0xff;
\r
47 code[codesize++] = (value>>16)&0xff;
\r
48 code[codesize++] = (value>>24)&0xff;
\r
50 void EmitAdr(void *value)
\r
52 Emit4Byte((unsigned int)value);
\r
54 void EmitFloat(float value)
\r
56 union {float f; unsigned int i;} u;
\r
60 void Emit2Byte(unsigned short value)
\r
62 code[codesize++] = (value>> 0)&0xff;
\r
63 code[codesize++] = (value>> 8)&0xff;
\r
66 void EmitFOffset(void *func, int bias)
\r
68 union {void *f; unsigned int i;} u;
\r
70 u.i -= (unsigned int)&code[codesize+bias];
\r
74 void Emit4ByteJump(int statementnum, int offset)
\r
76 statementjumps[numjumps++] = codesize;
\r
77 statementjumps[numjumps++] = statementnum;
\r
78 statementjumps[numjumps++] = offset;
\r
80 //the offset is filled in later
\r
84 void FixupJumps(void)
\r
87 unsigned char *codesrc;
\r
88 unsigned char *codedst;
\r
89 unsigned int offset;
\r
93 for (j = 0; j < numjumps;)
\r
95 v = statementjumps[j++];
\r
98 v = statementjumps[j++];
\r
99 codedst = statementoffsets[v];
\r
101 v = statementjumps[j++];
\r
102 offset = (int)(codedst - (codesrc-v)); //3rd term because the jump is relative to the instruction start, not the instruction's offset
\r
104 codesrc[0] = (offset>> 0)&0xff;
\r
105 codesrc[1] = (offset>> 8)&0xff;
\r
106 codesrc[2] = (offset>>16)&0xff;
\r
107 codesrc[3] = (offset>>24)&0xff;
\r
111 int PR_LeaveFunction (progfuncs_t *progfuncs);
\r
112 int PR_EnterFunction (progfuncs_t *progfuncs, dfunction_t *f, int progsnum);
\r
114 pbool PR_GenerateJit(progfuncs_t *progfuncs)
\r
117 dstatement16_t *op = (dstatement16_t*)current_progstate->statements;
\r
118 unsigned int numstatements = current_progstate->progs->numstatements;
\r
119 int *glob = (int*)current_progstate->globals;
\r
121 if (current_progstate->numbuiltins)
\r
124 jitstatements = numstatements;
\r
126 statementjumps = malloc(numstatements*12);
\r
127 statementoffsets = malloc(numstatements*4);
\r
128 code = malloc(numstatements*500);
\r
135 for (i = 0; i < numstatements; i++)
\r
137 statementoffsets[i] = &code[codesize];
\r
146 EmitByte(0x83);EmitByte(0x3d);EmitAdr(glob + op[i].a);EmitByte(0x0);
\r
148 EmitByte(0x0f);EmitByte(0x85);Emit4ByteJump(i + (signed short)op[i].b, -4);
\r
156 EmitByte(0x83);EmitByte(0x3d);EmitAdr(glob + op[i].a);EmitByte(0x0);
\r
158 EmitByte(0x0f);EmitByte(0x84);Emit4ByteJump(i + (signed short)op[i].b, -4);
\r
162 EmitByte(0xE9);Emit4ByteJump(i + (signed short)op[i].a, -4);
\r
168 //done and return are the same
\r
170 //part 1: store A into OFS_RETURN
\r
174 //assumption: anything that returns address 0 is a void or zero return.
\r
175 //thus clear eax and copy that to the return vector.
\r
176 EmitByte(0x31);EmitByte(0xc0);
\r
177 EmitByte(0xa3);EmitAdr(glob + OFS_RETURN+0);
\r
178 EmitByte(0xa3);EmitAdr(glob + OFS_RETURN+1);
\r
179 EmitByte(0xa3);EmitAdr(glob + OFS_RETURN+2);
\r
183 //movl glob[A+0],eax
\r
184 EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
\r
185 //movl glob[A+0],edx
\r
186 EmitByte(0x8b);EmitByte(0x0d);EmitAdr(glob + op[i].a+1);
\r
187 //movl glob[A+0],ecx
\r
188 EmitByte(0x8b);EmitByte(0x15);EmitAdr(glob + op[i].a+2);
\r
189 //movl eax, glob[OFS_RET+0]
\r
190 EmitByte(0xa3);EmitAdr(glob + OFS_RETURN+0);
\r
191 //movl edx, glob[OFS_RET+0]
\r
192 EmitByte(0x89);EmitByte(0x15);EmitAdr(glob + OFS_RETURN+1);
\r
193 //movl ecx, glob[OFS_RET+0]
\r
194 EmitByte(0x89);EmitByte(0x15);EmitAdr(glob + OFS_RETURN+2);
\r
197 //call leavefunction to get the return address
\r
200 EmitByte(0x68);EmitAdr(progfuncs);
\r
201 // call PR_LeaveFunction
\r
202 EmitByte(0xe8);EmitFOffset(PR_LeaveFunction, 4);
\r
204 EmitByte(0x83);EmitByte(0xc4);EmitByte(0x04);
\r
205 // movl pr_depth,%edx
\r
206 EmitByte(0x8b);EmitByte(0x15);EmitAdr(&pr_depth);
\r
207 // cmp prinst->exitdepth,%edx
\r
208 EmitByte(0x3b);EmitByte(0x15);EmitAdr(&prinst->exitdepth);
\r
210 EmitByte(0x74);EmitByte(0x09);
\r
211 // mov statementoffsets[%eax*4],%eax
\r
212 EmitByte(0x8b);EmitByte(0x04);EmitByte(0x85);EmitAdr(statementoffsets+1);
\r
214 EmitByte(0xff);EmitByte(0xe0);
\r
230 //save the state in place the rest of the engine can cope with
\r
231 //movl $i, pr_xstatement
\r
232 EmitByte(0xc7);EmitByte(0x05);EmitAdr(&pr_xstatement);Emit4Byte(i);
\r
233 //movl $(op[i].op-OP_CALL0), pr_argc
\r
234 EmitByte(0xc7);EmitByte(0x05);EmitAdr(&pr_argc);Emit4Byte(op[i].op-OP_CALL0);
\r
236 //figure out who we're calling, and what that involves
\r
238 EmitByte(0xa1); EmitAdr(glob + op[i].a);
\r
239 //eax is now the func num
\r
242 EmitByte(0x89); EmitByte(0xc1);
\r
244 EmitByte(0xc1); EmitByte(0xe9); EmitByte(0x18);
\r
245 //ecx is now the progs num for the new func
\r
247 //cmp %ecx,pr_typecurrent
\r
248 EmitByte(0x39); EmitByte(0x0d); EmitAdr(&pr_typecurrent);
\r
250 EmitByte(0x74); EmitByte(0x3);
\r
252 //can't handle switching progs
\r
254 //FIXME: recurse though PR_ExecuteProgram
\r
257 //call PR_ExecuteProgram
\r
259 //remember to change the je above
\r
261 //err... exit depth? no idea
\r
262 EmitByte(0xcd);EmitByte(op[i].op); //int $X
\r
270 //andl $0x00ffffff, %eax
\r
271 EmitByte(0x25);Emit4Byte(0x00ffffff);
\r
273 //mov $sizeof(dfunction_t),%edx
\r
274 EmitByte(0xba);Emit4Byte(sizeof(dfunction_t));
\r
276 EmitByte(0xf7); EmitByte(0xe2);
\r
277 //add pr_functions,%eax
\r
278 EmitByte(0x05); EmitAdr(pr_functions);
\r
280 //eax is now the dfunction_t to be called
\r
281 //edx is clobbered.
\r
284 EmitByte(0x8b);EmitByte(0x10);
\r
285 //edx is now the first statement number
\r
287 EmitByte(0x83);EmitByte(0xfa);EmitByte(0x00);
\r
289 EmitByte(0x7c);EmitByte(22);
\r
297 EmitByte(0x68);EmitAdr(progfuncs);
\r
298 //call PR_EnterFunction
\r
299 EmitByte(0xe8);EmitFOffset(PR_EnterFunction, 4);
\r
301 EmitByte(0x83);EmitByte(0xc4);EmitByte(0xc);
\r
302 //eax is now the next statement number (first of the new function, usually equal to ecx, but not always)
\r
304 //jmp statementoffsets[%eax*4]
\r
305 EmitByte(0xff);EmitByte(0x24);EmitByte(0x85);EmitAdr(statementoffsets+1);
\r
310 //push current_progstate->globals
\r
311 EmitByte(0x68);EmitAdr(current_progstate->globals);
\r
313 EmitByte(0x68);EmitAdr(progfuncs);
\r
315 EmitByte(0xf7);EmitByte(0xda);
\r
316 //call externs->globalbuiltins[%edx,4]
\r
317 //FIXME: make sure this dereferences
\r
318 EmitByte(0xff);EmitByte(0x14);EmitByte(0x95);EmitAdr(externs->globalbuiltins);
\r
320 EmitByte(0x83);EmitByte(0xc4);EmitByte(0x8);
\r
322 //but that builtin might have been Abort()
\r
324 //mov prinst->continuestatement,%eax
\r
325 EmitByte(0xa1);EmitAdr(&prinst->continuestatement);
\r
326 //eax is now prinst->continuestatement
\r
329 EmitByte(0x83);EmitByte(0xf8);EmitByte(0xff);
\r
330 //je donebuiltincall
\r
331 EmitByte(0x74);EmitByte(10+8);
\r
334 //jmp statementoffsets[%eax*4]
\r
335 EmitByte(0xff);EmitByte(0x24);EmitByte(0x85);EmitAdr(statementoffsets+1);
\r
337 //mov $-1,prinst->continuestatement
\r
338 EmitByte(0xc7);EmitByte(0x05);EmitAdr(&prinst->continuestatement+1);Emit4Byte((unsigned int)-1);
\r
345 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
\r
347 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b);
\r
349 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
\r
353 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
\r
355 EmitByte(0xd8);EmitByte(0x35);EmitAdr(glob + op[i].b);
\r
357 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
\r
361 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
\r
363 EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b);
\r
365 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
\r
369 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
\r
371 EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b);
\r
373 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
\r
378 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
\r
380 EmitByte(0xd9);EmitByte(0xee);
\r
382 EmitByte(0xdf);EmitByte(0xe0);
\r
384 EmitByte(0xf6);EmitByte(0xc4);EmitByte(0x40);
\r
386 EmitByte(0x74);EmitByte(0x0c);
\r
387 //movl 1.0f,glob[C]
\r
388 EmitByte(0xc7);EmitByte(0x05);EmitAdr(glob + op[i].c);EmitFloat(0.0f);
\r
390 EmitByte(0xeb);EmitByte(0x0a);
\r
392 //movl 0.0f,glob[C]
\r
393 EmitByte(0xc7);EmitByte(0x05);EmitAdr(glob + op[i].c);EmitFloat(1.0f);
\r
403 EmitByte(0xa1);EmitAdr(glob + op[i].a);
\r
405 EmitByte(0xa3);EmitAdr(glob + op[i].b);
\r
409 //movl glob[A+0],eax
\r
410 EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
\r
411 //movl glob[A+1],edx
\r
412 EmitByte(0x8b);EmitByte(0x0d);EmitAdr(glob + op[i].a+1);
\r
413 //movl glob[A+2],ecx
\r
414 EmitByte(0x8b);EmitByte(0x15);EmitAdr(glob + op[i].a+2);
\r
416 //movl eax, glob[B+0]
\r
417 EmitByte(0xa3);EmitAdr(glob + op[i].b+0);
\r
418 //movl edx, glob[B+1]
\r
419 EmitByte(0x89);EmitByte(0x15);EmitAdr(glob + op[i].b+1);
\r
420 //movl ecx, glob[B+2]
\r
421 EmitByte(0x89);EmitByte(0x15);EmitAdr(glob + op[i].b+2);
\r
430 //a is the ent number, b is the field
\r
433 //movl glob[A+0],eax
\r
434 EmitByte(0xa1);EmitAdr(glob + op[i].a);
\r
436 EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);
\r
437 //FIXME: bound eax (ent number)
\r
438 //FIXME: bound ecx (field index)
\r
439 //mov (ebx,eax,4).%eax
\r
440 EmitByte(0x8b); EmitByte(0x04); EmitByte(0x83);
\r
441 //eax is now an edictrun_t
\r
442 //mov fields(,%eax,4),%edx
\r
443 EmitByte(0x8b);EmitByte(0x50);EmitByte((int)&((edictrun_t*)NULL)->fields);
\r
444 //edx is now the field array for that ent
\r
446 //mov fieldajust(%edx,%ecx,4),%eax //offset = progfuncs->fieldadjust
\r
447 EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(progfuncs->fieldadjust*4);
\r
449 EmitByte(0xa3);EmitAdr(glob + op[i].c);
\r
451 if (op[i].op == OP_LOAD_V)
\r
453 //mov fieldajust+4(%edx,%ecx,4),%eax //offset = progfuncs->fieldadjust
\r
454 EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(4+progfuncs->fieldadjust*4);
\r
455 //mov edx,glob[C+1]
\r
456 EmitByte(0xa3);EmitAdr(glob + op[i].c+1);
\r
458 //mov fieldajust+8(%edx,%ecx,4),%eax //offset = progfuncs->fieldadjust
\r
459 EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(4+progfuncs->fieldadjust*4);
\r
460 //mov edx,glob[C+1]
\r
461 EmitByte(0xa3);EmitAdr(glob + op[i].c+2);
\r
466 //a is the ent number, b is the field
\r
469 //movl glob[A+0],eax
\r
470 EmitByte(0xa1);EmitAdr(glob + op[i].a);
\r
472 EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);
\r
473 //FIXME: bound eax (ent number)
\r
474 //FIXME: bound ecx (field index)
\r
475 //mov (ebx,eax,4).%eax
\r
476 EmitByte(0x8b); EmitByte(0x04); EmitByte(0x83);
\r
477 //eax is now an edictrun_t
\r
478 //mov fields(,%eax,4),%edx
\r
479 EmitByte(0x8b);EmitByte(0x50);EmitByte((int)&((edictrun_t*)NULL)->fields);
\r
480 //edx is now the field array for that ent
\r
481 //mov fieldajust(%edx,%ecx,4),%eax //offset = progfuncs->fieldadjust
\r
482 //EmitByte(0x8d); EmitByte(0x84); EmitByte(0x8a); EmitByte(progfuncs->fieldadjust*4);
\r
483 EmitByte(0x8d); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(progfuncs->fieldadjust*4);
\r
485 EmitByte(0xa3);EmitAdr(glob + op[i].c);
\r
490 case OP_STOREP_ENT:
\r
491 case OP_STOREP_FLD:
\r
492 case OP_STOREP_FNC:
\r
494 EmitByte(0xa1);EmitAdr(glob + op[i].a);
\r
496 EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);
\r
498 EmitByte(0x89);EmitByte(0x01);
\r
503 EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);
\r
505 EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
\r
507 EmitByte(0x89);EmitByte(0x01);
\r
509 EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
\r
511 EmitByte(0x89);EmitByte(0x41);EmitByte(0x04);
\r
513 EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
\r
515 EmitByte(0x89);EmitByte(0x41);EmitByte(0x08);
\r
521 //movl glob[A],%eax
\r
522 EmitByte(0xa1);EmitAdr(glob + op[i].a);
\r
524 EmitByte(0x3b); EmitByte(0x0f); EmitAdr(glob + op[i].b);
\r
526 EmitByte(0x74);EmitByte(0x0c);
\r
528 EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(0.0f);
\r
530 EmitByte(0xeb);EmitByte(0x0a);
\r
532 EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(1.0f);
\r
538 //movl glob[A],%eax
\r
539 EmitByte(0xa1);EmitAdr(glob + op[i].a);
\r
541 EmitByte(0x3b); EmitByte(0x0f); EmitAdr(glob + op[i].b);
\r
543 EmitByte(0x74);EmitByte(0x0c);
\r
545 EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(1.0f);
\r
547 EmitByte(0xeb);EmitByte(0x0a);
\r
549 EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(0.0f);
\r
555 EmitByte(0x8c); EmitByte(0x3d); EmitAdr(glob + op[i].a);EmitByte(0x00);
\r
557 EmitByte(0x74);EmitByte(0x0c);
\r
559 EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(0.0f);
\r
561 EmitByte(0xeb);EmitByte(0x0a);
\r
563 EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].c);EmitFloat(1.0f);
\r
566 case OP_BITOR: //floats...
\r
568 EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].a);
\r
570 EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].b);
\r
572 EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&tb);
\r
574 EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&ta);
\r
576 EmitByte(0xa1); EmitAdr(&ta);
\r
578 EmitByte(0x09); EmitByte(0x05);EmitAdr(&tb);
\r
580 EmitByte(0xdf); EmitByte(0x05);EmitAdr(&tb);
\r
582 EmitByte(0xd9); EmitByte(0x1d);EmitAdr(glob + op[i].c);
\r
587 EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].a);
\r
589 EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].b);
\r
591 EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&tb);
\r
593 EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&ta);
\r
595 EmitByte(0xa1); EmitAdr(&ta);
\r
597 EmitByte(0x21); EmitByte(0x05);EmitAdr(&tb);
\r
599 EmitByte(0xdf); EmitByte(0x05);EmitAdr(&tb);
\r
601 EmitByte(0xd9); EmitByte(0x1d);EmitAdr(glob + op[i].c);
\r
605 //test floats properly, so we don't get confused with -0.0
\r
608 EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].a);
\r
610 EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);
\r
612 EmitByte(0xdf); EmitByte(0xe0);
\r
614 EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);
\r
616 EmitByte(0x75); EmitByte(0x1f);
\r
619 EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].b);
\r
621 EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);
\r
623 EmitByte(0xdf); EmitByte(0xe0);
\r
625 EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);
\r
627 EmitByte(0x75); EmitByte(0x0c);
\r
629 //mov float0,glob[C]
\r
630 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);
\r
632 EmitByte(0xeb); EmitByte(0x0a);
\r
635 //mov float1,glob[C]
\r
636 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);
\r
640 //test floats properly, so we don't get confused with -0.0
\r
643 EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].a);
\r
645 EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);
\r
647 EmitByte(0xdf); EmitByte(0xe0);
\r
649 EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);
\r
651 EmitByte(0x74); EmitByte(0x1f);
\r
654 EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].b);
\r
656 EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);
\r
658 EmitByte(0xdf); EmitByte(0xe0);
\r
660 EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);
\r
662 EmitByte(0x74); EmitByte(0x0c);
\r
664 //mov float0,glob[C]
\r
665 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);
\r
667 EmitByte(0xeb); EmitByte(0x0a);
\r
670 //mov float1,glob[C]
\r
671 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);
\r
680 EmitByte(0x8b); EmitByte(0x0d); EmitAdr(glob + op[i].a);
\r
682 EmitByte(0x8b); EmitByte(0x3d); EmitAdr(glob + op[i].b);
\r
684 //early out if they're equal
\r
686 EmitByte(0x39); EmitByte(0xd1);
\r
688 EmitByte(0x74); EmitByte(0x68);
\r
690 //if a is 0, check if b is ""
\r
692 EmitByte(0xe3); EmitByte(0x1a);
\r
694 //if b is 0, check if a is ""
\r
696 EmitByte(0x83); EmitByte(0xff); EmitByte(0x00);
\r
698 EmitByte(0x75); EmitByte(0x2a);
\r
703 EmitByte(0x68); EmitAdr(progfuncs);
\r
704 //call PR_StringToNative
\r
705 EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
\r
707 EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);
\r
709 EmitByte(0x80); EmitByte(0x38); EmitByte(0x00);
\r
711 EmitByte(0x74); EmitByte(0x4b);
\r
713 EmitByte(0xeb); EmitByte(0x3d);
\r
720 EmitByte(0x68); EmitAdr(progfuncs);
\r
721 //call PR_StringToNative
\r
722 EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
\r
724 EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);
\r
726 EmitByte(0x80); EmitByte(0x38); EmitByte(0x00);
\r
728 EmitByte(0x74); EmitByte(0x36);
\r
730 EmitByte(0xeb); EmitByte(0x28);
\r
738 EmitByte(0x68); EmitAdr(progfuncs);
\r
739 //call PR_StringToNative
\r
740 EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
\r
747 EmitByte(0x68); EmitAdr(progfuncs);
\r
748 //call PR_StringToNative
\r
749 EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
\r
751 EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);
\r
757 EmitByte(0xe8); EmitFOffset(strcmp,4);
\r
759 EmitByte(0x83); EmitByte(0xc4); EmitByte(0x10);
\r
761 EmitByte(0x83); EmitByte(0xf8); EmitByte(0x00);
\r
763 EmitByte(0x74); EmitByte(0x0c);
\r
766 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat((op[i].op == OP_NE_S)?1.0f:0.0f);
\r
768 EmitByte(0xeb); EmitByte(0x0a);
\r
771 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat((op[i].op == OP_NE_S)?0.0f:1.0f);
\r
777 EmitByte(0xa1);EmitAdr(glob + op[i].a);
\r
779 EmitByte(0x83); EmitByte(0xf8); EmitByte(0x00);
\r
781 EmitByte(0x74); EmitByte(0x1f);
\r
785 EmitByte(0x68); EmitAdr(progfuncs);
\r
786 //call PR_StringToNative
\r
787 EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
\r
789 EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);
\r
791 EmitByte(0x80); EmitByte(0x38); EmitByte(0x00);
\r
793 EmitByte(0x74); EmitByte(0x0c);
\r
796 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);
\r
798 EmitByte(0xeb); EmitByte(0x0a);
\r
801 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);
\r
807 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);
\r
809 EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b+0);
\r
811 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+0);
\r
814 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+1);
\r
816 EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b+1);
\r
818 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+1);
\r
821 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+2);
\r
823 EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b+2);
\r
825 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+2);
\r
829 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);
\r
831 EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b+0);
\r
833 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+0);
\r
836 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+1);
\r
838 EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b+1);
\r
840 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+1);
\r
843 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+2);
\r
845 EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b+2);
\r
847 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+2);
\r
851 //this is actually a dotproduct
\r
853 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);
\r
855 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b+0);
\r
858 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+1);
\r
860 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b+1);
\r
863 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+2);
\r
865 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b+2);
\r
868 EmitByte(0xde);EmitByte(0xc1);
\r
870 EmitByte(0xde);EmitByte(0xc1);
\r
873 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
\r
883 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
\r
885 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].b);
\r
886 //fcomip %st(1),%st
\r
887 EmitByte(0xdf);EmitByte(0xe9);
\r
888 //fstp %st(0) (aka: pop)
\r
889 EmitByte(0xdd);EmitByte(0xd8);
\r
892 if (op[i].op == OP_LE)
\r
893 EmitByte(0x7e); //jle
\r
894 else if (op[i].op == OP_GE)
\r
895 EmitByte(0x7d); //jge
\r
896 else if (op[i].op == OP_LT)
\r
897 EmitByte(0x7c); //jl
\r
898 else if (op[i].op == OP_GT)
\r
899 EmitByte(0x7f); //jg
\r
900 else if (op[i].op == OP_NE_F)
\r
901 EmitByte(0x75); //jne
\r
903 EmitByte(0x74); //je
\r
907 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);
\r
909 EmitByte(0xeb); EmitByte(0x0a);
\r
912 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);
\r
922 if (op[i].op == OP_MUL_FV)
\r
934 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + f);
\r
937 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + v+0);
\r
939 EmitByte(0xd8);EmitByte(0xc9);
\r
941 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+0);
\r
944 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + v+1);
\r
946 EmitByte(0xd8);EmitByte(0xc9);
\r
948 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+1);
\r
951 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + v+2);
\r
953 EmitByte(0xd8);EmitByte(0xc9);
\r
955 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+2);
\r
957 //fstp %st(0) (aka: pop)
\r
958 EmitByte(0xdd);EmitByte(0xd8);
\r
963 //externs->stateop(progfuncs, OPA->_float, OPB->function);
\r
965 EmitByte(0xff);EmitByte(0x35);EmitAdr(glob + op[i].b);
\r
967 EmitByte(0xff);EmitByte(0x35);EmitAdr(glob + op[i].a);
\r
969 EmitByte(0x68); EmitAdr(progfuncs);
\r
970 //call externs->stateop
\r
971 EmitByte(0xe8); EmitFOffset(externs->stateop, 4);
\r
973 EmitByte(0x83); EmitByte(0xc4); EmitByte(0x0c);
\r
979 //fcomip %st(1),%st
\r
982 //fcomip %st(1),%st
\r
985 //fcomip %st(1),%st
\r
996 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);
\r
998 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].b+0);
\r
999 //fcomip %st(1),%st
\r
1000 EmitByte(0xdf);EmitByte(0xe9);
\r
1001 //fstp %st(0) (aka: pop)
\r
1002 EmitByte(0xdd);EmitByte(0xd8);
\r
1005 if (op[i].op == OP_NE_V)
\r
1006 EmitByte(0x74); //je
\r
1008 EmitByte(0x75); //jne
\r
1012 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);
\r
1014 EmitByte(0xeb); EmitByte(0x0a);
\r
1019 EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);
\r
1025 EmitByte(0xcd);EmitByte(op[i].op);
\r
1026 printf("QCJIT: instruction %i is not implemented\n", op[i].op);
\r
1030 EmitByte(0xcd);EmitByte(op[i].op);
\r
1031 printf("QCJIT: instruction %i is not implemented\n", op[i].op);
\r
1035 EmitByte(0xcd);EmitByte(op[i].op);
\r
1036 printf("QCJIT: instruction %i is not implemented\n", op[i].op);
\r
1040 printf("QCJIT: Extended instruction set %i is not supported, not using jit.\n", op[i].op);
\r
1043 free(statementjumps); //[MAX_STATEMENTS]
\r
1044 free(statementoffsets); //[MAX_STATEMENTS]
\r
1046 statementoffsets = NULL;
\r
1057 //this memory is on the heap.
\r
1058 //this means that we must maintain read/write protection, or libc will crash us
\r
1059 VirtualProtect(code, codesize, PAGE_EXECUTE_READWRITE, &old);
\r
1063 // externs->WriteFile("jit.x86", code, codesize);
\r
1068 void PR_EnterJIT(progfuncs_t *progfuncs, int statement)
\r
1071 //call, it clobbers pretty much everything.
\r
1072 asm("call *%0" :: "r"(statementoffsets[statement+1]),"b"(prinst->edicttable):"cc","memory","eax","ecx","edx");
\r
1073 #elif defined(_MSC_VER)
\r
1074 void *entry = statementoffsets[statement+1];
\r
1075 void *edicttable = prinst->edicttable;
\r
1079 mov ebx,edicttable
\r
1084 #error "Sorry, no idea how to enter assembler safely for your compiler"
\r