]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - misc/source/fteqcc-src/pr_x86.c
Use pow() for all scale differences, which should make them much more correct, and...
[voretournament/voretournament.git] / misc / source / fteqcc-src / pr_x86.c
1 /*\r
2 when I say JIT, I mean load time, not execution time.\r
3 \r
4 notes:\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
7 \r
8 optimisations:\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
12 \r
13         eax - tmp\r
14         ebx - prinst->edicttable\r
15         ecx     - tmp\r
16         edx - tmp\r
17         esi - \r
18         edi - tmp (because its preserved by subfunctions\r
19         ebp - \r
20 \r
21   to use gas to provide binary opcodes:\r
22   vim -N blob.s && as blob.s && objdump.exe -d a.out\r
23 */\r
24 \r
25 #define PROGSUSED\r
26 #include "progsint.h"\r
27 \r
28 #ifdef QCJIT\r
29 \r
30 static float ta, tb, nullfloat=0;\r
31 \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
38 \r
39 void EmitByte(unsigned char byte)\r
40 {\r
41         code[codesize++] = byte;\r
42 }\r
43 void Emit4Byte(unsigned int value)\r
44 {\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
49 }\r
50 void EmitAdr(void *value)\r
51 {\r
52         Emit4Byte((unsigned int)value);\r
53 }\r
54 void EmitFloat(float value)\r
55 {\r
56         union {float f; unsigned int i;} u;\r
57         u.f = value;\r
58         Emit4Byte(u.i);\r
59 }\r
60 void Emit2Byte(unsigned short value)\r
61 {\r
62         code[codesize++] = (value>> 0)&0xff;\r
63         code[codesize++] = (value>> 8)&0xff;\r
64 }\r
65 \r
66 void EmitFOffset(void *func, int bias)\r
67 {\r
68         union {void *f; unsigned int i;} u;\r
69         u.f = func;\r
70         u.i -= (unsigned int)&code[codesize+bias];\r
71         Emit4Byte(u.i);\r
72 }\r
73 \r
74 void Emit4ByteJump(int statementnum, int offset)\r
75 {\r
76         statementjumps[numjumps++] = codesize;\r
77         statementjumps[numjumps++] = statementnum;\r
78         statementjumps[numjumps++] = offset;\r
79 \r
80         //the offset is filled in later\r
81         codesize += 4;\r
82 }\r
83 \r
84 void FixupJumps(void)\r
85 {\r
86         unsigned int j;\r
87         unsigned char *codesrc;\r
88         unsigned char *codedst;\r
89         unsigned int offset;\r
90 \r
91         unsigned int v;\r
92 \r
93         for (j = 0; j < numjumps;)\r
94         {\r
95                 v = statementjumps[j++];\r
96                 codesrc = &code[v];\r
97 \r
98                 v = statementjumps[j++];\r
99                 codedst = statementoffsets[v];\r
100 \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
103 \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
108         }\r
109 }\r
110 \r
111 int PR_LeaveFunction (progfuncs_t *progfuncs);\r
112 int PR_EnterFunction (progfuncs_t *progfuncs, dfunction_t *f, int progsnum);\r
113 \r
114 pbool PR_GenerateJit(progfuncs_t *progfuncs)\r
115 {\r
116         unsigned int i;\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
120 \r
121         if (current_progstate->numbuiltins)\r
122                 return false;\r
123 \r
124         jitstatements = numstatements;\r
125 \r
126         statementjumps = malloc(numstatements*12);\r
127         statementoffsets = malloc(numstatements*4);\r
128         code = malloc(numstatements*500);\r
129 \r
130         numjumps = 0;\r
131         codesize = 0;\r
132 \r
133 \r
134 \r
135         for (i = 0; i < numstatements; i++)\r
136         {\r
137                 statementoffsets[i] = &code[codesize];\r
138                 switch(op[i].op)\r
139                 {\r
140                 //jumps\r
141                 case OP_IF:\r
142                         //integer compare\r
143                         //if a, goto b\r
144 \r
145                         //cmpl $0,glob[A]\r
146                         EmitByte(0x83);EmitByte(0x3d);EmitAdr(glob + op[i].a);EmitByte(0x0);\r
147                         //jnz B\r
148                         EmitByte(0x0f);EmitByte(0x85);Emit4ByteJump(i + (signed short)op[i].b, -4);\r
149                         break;\r
150 \r
151                 case OP_IFNOT:\r
152                         //integer compare\r
153                         //if !a, goto b\r
154 \r
155                         //cmpl $0,glob[A]\r
156                         EmitByte(0x83);EmitByte(0x3d);EmitAdr(glob + op[i].a);EmitByte(0x0);\r
157                         //jz B\r
158                         EmitByte(0x0f);EmitByte(0x84);Emit4ByteJump(i + (signed short)op[i].b, -4);\r
159                         break;\r
160 \r
161                 case OP_GOTO:\r
162                         EmitByte(0xE9);Emit4ByteJump(i + (signed short)op[i].a, -4);\r
163                         break;\r
164                         \r
165                 //function returns\r
166                 case OP_DONE:\r
167                 case OP_RETURN:\r
168                         //done and return are the same\r
169 \r
170                         //part 1: store A into OFS_RETURN\r
171 \r
172                         if (!op[i].a)\r
173                         {\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
180                         }\r
181                         else\r
182                         {\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
195                         }\r
196                         \r
197                         //call leavefunction to get the return address\r
198                         \r
199 //                      pushl progfuncs\r
200                         EmitByte(0x68);EmitAdr(progfuncs);\r
201 //                      call PR_LeaveFunction\r
202                         EmitByte(0xe8);EmitFOffset(PR_LeaveFunction, 4);\r
203 //                      add $4,%esp\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
209 //                      je returntoc\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
213 //                      jmp eax\r
214                         EmitByte(0xff);EmitByte(0xe0);\r
215 //                      returntoc:\r
216 //                      ret\r
217                         EmitByte(0xc3);\r
218                         break;\r
219 \r
220                 //function calls\r
221                 case OP_CALL0:\r
222                 case OP_CALL1:\r
223                 case OP_CALL2:\r
224                 case OP_CALL3:\r
225                 case OP_CALL4:\r
226                 case OP_CALL5:\r
227                 case OP_CALL6:\r
228                 case OP_CALL7:\r
229                 case OP_CALL8:\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
235 \r
236                 //figure out who we're calling, and what that involves\r
237                         //%eax = glob[A]\r
238                         EmitByte(0xa1); EmitAdr(glob + op[i].a);\r
239                 //eax is now the func num\r
240 \r
241                         //mov %eax,%ecx\r
242                         EmitByte(0x89); EmitByte(0xc1);\r
243                         //shr $24,%ecx\r
244                         EmitByte(0xc1); EmitByte(0xe9); EmitByte(0x18);\r
245                 //ecx is now the progs num for the new func\r
246 \r
247                         //cmp %ecx,pr_typecurrent\r
248                         EmitByte(0x39); EmitByte(0x0d); EmitAdr(&pr_typecurrent);\r
249                         //je sameprogs\r
250                         EmitByte(0x74); EmitByte(0x3);\r
251                         {\r
252                                 //can't handle switching progs\r
253 \r
254                                 //FIXME: recurse though PR_ExecuteProgram\r
255                                 //push eax\r
256                                 //push progfuncs\r
257                                 //call PR_ExecuteProgram\r
258                                 //add $8,%esp\r
259                                 //remember to change the je above\r
260 \r
261                                 //err... exit depth? no idea\r
262                                 EmitByte(0xcd);EmitByte(op[i].op);      //int $X\r
263 \r
264 \r
265                                 //ret\r
266                                 EmitByte(0xc3);\r
267                         }\r
268                         //sameprogs:\r
269 \r
270                         //andl $0x00ffffff, %eax\r
271                         EmitByte(0x25);Emit4Byte(0x00ffffff);\r
272                         \r
273                         //mov $sizeof(dfunction_t),%edx\r
274                         EmitByte(0xba);Emit4Byte(sizeof(dfunction_t));\r
275                         //mul %edx\r
276                         EmitByte(0xf7); EmitByte(0xe2);\r
277                         //add pr_functions,%eax\r
278                         EmitByte(0x05); EmitAdr(pr_functions);\r
279 \r
280                 //eax is now the dfunction_t to be called\r
281                 //edx is clobbered.\r
282 \r
283                         //mov (%eax),%edx\r
284                         EmitByte(0x8b);EmitByte(0x10);\r
285                 //edx is now the first statement number\r
286                         //cmp $0,%edx\r
287                         EmitByte(0x83);EmitByte(0xfa);EmitByte(0x00);\r
288                         //jl isabuiltin\r
289                         EmitByte(0x7c);EmitByte(22);\r
290         \r
291                         {\r
292                                 //push %ecx\r
293                                 EmitByte(0x51);\r
294                                 //push %eax\r
295                                 EmitByte(0x50);\r
296                                 //pushl progfuncs\r
297                                 EmitByte(0x68);EmitAdr(progfuncs);\r
298                                 //call PR_EnterFunction\r
299                                 EmitByte(0xe8);EmitFOffset(PR_EnterFunction, 4);\r
300                                 //sub $12,%esp\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
303 \r
304                                 //jmp statementoffsets[%eax*4]\r
305                                 EmitByte(0xff);EmitByte(0x24);EmitByte(0x85);EmitAdr(statementoffsets+1);\r
306                         }\r
307                         //isabuiltin:\r
308 \r
309 \r
310                         //push current_progstate->globals\r
311                         EmitByte(0x68);EmitAdr(current_progstate->globals);\r
312                         //push progfuncs\r
313                         EmitByte(0x68);EmitAdr(progfuncs);\r
314                         //neg %edx\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
319                         //add $8,%esp\r
320                         EmitByte(0x83);EmitByte(0xc4);EmitByte(0x8);\r
321 \r
322                 //but that builtin might have been Abort()\r
323 \r
324                         //mov prinst->continuestatement,%eax\r
325                         EmitByte(0xa1);EmitAdr(&prinst->continuestatement);\r
326                 //eax is now prinst->continuestatement\r
327 \r
328                         //cmp $-1,%eax\r
329                         EmitByte(0x83);EmitByte(0xf8);EmitByte(0xff);\r
330                         //je donebuiltincall\r
331                         EmitByte(0x74);EmitByte(10+8);\r
332                         {\r
333 EmitByte(0xcc);\r
334                                 //jmp statementoffsets[%eax*4]\r
335                                 EmitByte(0xff);EmitByte(0x24);EmitByte(0x85);EmitAdr(statementoffsets+1);\r
336 \r
337                                 //mov $-1,prinst->continuestatement\r
338                                 EmitByte(0xc7);EmitByte(0x05);EmitAdr(&prinst->continuestatement+1);Emit4Byte((unsigned int)-1);\r
339                         }\r
340                         //donebuiltincall:\r
341                         break;\r
342 \r
343                 case OP_MUL_F:\r
344                         //flds glob[A]\r
345                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);\r
346                         //fmuls glob[B]\r
347                         EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b);\r
348                         //fstps glob[C]\r
349                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);\r
350                         break;\r
351                 case OP_DIV_F:\r
352                         //flds glob[A]\r
353                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);\r
354                         //fdivs glob[B]\r
355                         EmitByte(0xd8);EmitByte(0x35);EmitAdr(glob + op[i].b);\r
356                         //fstps glob[C]\r
357                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);\r
358                         break;\r
359                 case OP_ADD_F:\r
360                         //flds glob[A]\r
361                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);\r
362                         //fadds glob[B]\r
363                         EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b);\r
364                         //fstps glob[C]\r
365                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);\r
366                         break;\r
367                 case OP_SUB_F:\r
368                         //flds glob[A]\r
369                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);\r
370                         //fsubs glob[B]\r
371                         EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b);\r
372                         //fstps glob[C]\r
373                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);\r
374                         break;\r
375 \r
376                 case OP_NOT_F:\r
377                         //flds glob[A]\r
378                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);\r
379                         //fldz\r
380                         EmitByte(0xd9);EmitByte(0xee);\r
381                         //fnstsw %ax\r
382                         EmitByte(0xdf);EmitByte(0xe0);\r
383                         //testb 0x40,%ah\r
384                         EmitByte(0xf6);EmitByte(0xc4);EmitByte(0x40);\r
385                         //je noteq\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
389                         //jmp end\r
390                         EmitByte(0xeb);EmitByte(0x0a);\r
391                         //noteq:\r
392                         //movl 0.0f,glob[C]\r
393                         EmitByte(0xc7);EmitByte(0x05);EmitAdr(glob + op[i].c);EmitFloat(1.0f);\r
394                         //end:\r
395                         break;\r
396 \r
397                 case OP_STORE_F:\r
398                 case OP_STORE_S:\r
399                 case OP_STORE_ENT:\r
400                 case OP_STORE_FLD:\r
401                 case OP_STORE_FNC:\r
402                         //movl glob[A],eax\r
403                         EmitByte(0xa1);EmitAdr(glob + op[i].a);\r
404                         //movl eax,glob[B]\r
405                         EmitByte(0xa3);EmitAdr(glob + op[i].b);\r
406                         break;\r
407 \r
408                 case OP_STORE_V:\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
415 \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
422                         break;\r
423 \r
424                 case OP_LOAD_F:\r
425                 case OP_LOAD_S:\r
426                 case OP_LOAD_ENT:\r
427                 case OP_LOAD_FLD:\r
428                 case OP_LOAD_FNC:\r
429                 case OP_LOAD_V:\r
430                 //a is the ent number, b is the field\r
431                 //c is the dest\r
432 \r
433                         //movl glob[A+0],eax\r
434                         EmitByte(0xa1);EmitAdr(glob + op[i].a);\r
435                         //mov glob[B],ecx\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
445 \r
446                         //mov fieldajust(%edx,%ecx,4),%eax      //offset = progfuncs->fieldadjust\r
447                         EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(progfuncs->fieldadjust*4);\r
448                         //mov edx,glob[C]\r
449                         EmitByte(0xa3);EmitAdr(glob + op[i].c);\r
450 \r
451                         if (op[i].op == OP_LOAD_V)\r
452                         {\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
457 \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
462                         }\r
463                         break;\r
464 \r
465                 case OP_ADDRESS:\r
466                         //a is the ent number, b is the field\r
467                 //c is the dest\r
468 \r
469                         //movl glob[A+0],eax\r
470                         EmitByte(0xa1);EmitAdr(glob + op[i].a);\r
471                         //mov glob[B],ecx\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
484                         //mov edx,glob[C]\r
485                         EmitByte(0xa3);EmitAdr(glob + op[i].c);\r
486                         break;\r
487 \r
488                 case OP_STOREP_F:\r
489                 case OP_STOREP_S:\r
490                 case OP_STOREP_ENT:\r
491                 case OP_STOREP_FLD:\r
492                 case OP_STOREP_FNC:\r
493                         //movl glob[A],eax\r
494                         EmitByte(0xa1);EmitAdr(glob + op[i].a);\r
495                         //mov glob[B],ecx\r
496                         EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);\r
497                         //mov %eax,(%ecx)\r
498                         EmitByte(0x89);EmitByte(0x01);\r
499                         break;\r
500 \r
501                 case OP_STOREP_V:\r
502                         //mov glob[B],ecx\r
503                         EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);\r
504                         //movl glob[A],eax\r
505                         EmitByte(0xa1);EmitAdr(glob + op[i].a+0);\r
506                         //mov %eax,0(%ecx)\r
507                         EmitByte(0x89);EmitByte(0x01);\r
508                         //movl glob[A],eax\r
509                         EmitByte(0xa1);EmitAdr(glob + op[i].a+0);\r
510                         //mov %eax,4(%ecx)\r
511                         EmitByte(0x89);EmitByte(0x41);EmitByte(0x04);\r
512                         //movl glob[A],eax\r
513                         EmitByte(0xa1);EmitAdr(glob + op[i].a+0);\r
514                         //mov %eax,8(%ecx)\r
515                         EmitByte(0x89);EmitByte(0x41);EmitByte(0x08);\r
516                         break;\r
517 \r
518                 case OP_EQ_E:\r
519                 case OP_EQ_FNC:\r
520                         //integer equality\r
521                         //movl glob[A],%eax\r
522                         EmitByte(0xa1);EmitAdr(glob + op[i].a);\r
523                         //cmp glob[B],%eax\r
524                         EmitByte(0x3b); EmitByte(0x0f); EmitAdr(glob + op[i].b);\r
525                         //je 12\r
526                         EmitByte(0x74);EmitByte(0x0c);\r
527                         //mov 0.0f,glob[C]\r
528                         EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(0.0f);\r
529                         //jmp 10\r
530                         EmitByte(0xeb);EmitByte(0x0a);\r
531                         //mov 1.0f,glob[C]\r
532                         EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(1.0f);\r
533                         break;\r
534 \r
535                 case OP_NE_E:\r
536                 case OP_NE_FNC:\r
537                         //integer equality\r
538                         //movl glob[A],%eax\r
539                         EmitByte(0xa1);EmitAdr(glob + op[i].a);\r
540                         //cmp glob[B],%eax\r
541                         EmitByte(0x3b); EmitByte(0x0f); EmitAdr(glob + op[i].b);\r
542                         //je 12\r
543                         EmitByte(0x74);EmitByte(0x0c);\r
544                         //mov 0.0f,glob[C]\r
545                         EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(1.0f);\r
546                         //jmp 10\r
547                         EmitByte(0xeb);EmitByte(0x0a);\r
548                         //mov 1.0f,glob[C]\r
549                         EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(0.0f);\r
550                         break;\r
551 \r
552                 case OP_NOT_ENT:\r
553                 case OP_NOT_FNC:\r
554                         //cmp glob[B],%eax\r
555                         EmitByte(0x8c); EmitByte(0x3d); EmitAdr(glob + op[i].a);EmitByte(0x00);\r
556                         //je 12\r
557                         EmitByte(0x74);EmitByte(0x0c);\r
558                         //mov 0.0f,glob[C]\r
559                         EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(0.0f);\r
560                         //jmp 10\r
561                         EmitByte(0xeb);EmitByte(0x0a);\r
562                         //mov 1.0f,glob[C]\r
563                         EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].c);EmitFloat(1.0f);\r
564                         break;\r
565 \r
566                 case OP_BITOR:  //floats...\r
567                         //flds glob[A]\r
568                         EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].a);\r
569                         //flds glob[B]\r
570                         EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].b);\r
571                         //fistp tb\r
572                         EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&tb);\r
573                         //fistp ta\r
574                         EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&ta);\r
575                         //mov ta,%eax\r
576                         EmitByte(0xa1); EmitAdr(&ta);\r
577                         //and tb,%eax\r
578                         EmitByte(0x09); EmitByte(0x05);EmitAdr(&tb);\r
579                         //fild tb\r
580                         EmitByte(0xdf); EmitByte(0x05);EmitAdr(&tb);\r
581                         //fstps glob[C]\r
582                         EmitByte(0xd9); EmitByte(0x1d);EmitAdr(glob + op[i].c);\r
583                         break;\r
584 \r
585                 case OP_BITAND:\r
586                         //flds glob[A]\r
587                         EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].a);\r
588                         //flds glob[B]\r
589                         EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].b);\r
590                         //fistp tb\r
591                         EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&tb);\r
592                         //fistp ta\r
593                         EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&ta);\r
594                         //mov ta,%eax\r
595                         EmitByte(0xa1); EmitAdr(&ta);\r
596                         //and tb,%eax\r
597                         EmitByte(0x21); EmitByte(0x05);EmitAdr(&tb);\r
598                         //fild tb\r
599                         EmitByte(0xdf); EmitByte(0x05);EmitAdr(&tb);\r
600                         //fstps glob[C]\r
601                         EmitByte(0xd9); EmitByte(0x1d);EmitAdr(glob + op[i].c);\r
602                         break;\r
603 \r
604                 case OP_AND:\r
605                         //test floats properly, so we don't get confused with -0.0\r
606 \r
607                         //flds  glob[A]\r
608                         EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].a);\r
609                         //fcomps        nullfloat\r
610                         EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);\r
611                         //fnstsw        %ax\r
612                         EmitByte(0xdf); EmitByte(0xe0);\r
613                         //test  $0x40,%ah\r
614                         EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);\r
615                         //je onefalse\r
616                         EmitByte(0x75); EmitByte(0x1f);\r
617 \r
618                         //flds  glob[B]\r
619                         EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].b);\r
620                         //fcomps        nullfloat\r
621                         EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);\r
622                         //fnstsw        %ax\r
623                         EmitByte(0xdf); EmitByte(0xe0);\r
624                         //test  $0x40,%ah\r
625                         EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);\r
626                         //jne onefalse\r
627                         EmitByte(0x75); EmitByte(0x0c);\r
628 \r
629                         //mov float0,glob[C]\r
630                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);\r
631                         //jmp done\r
632                         EmitByte(0xeb); EmitByte(0x0a);\r
633 \r
634                         //onefalse:\r
635                         //mov float1,glob[C]\r
636                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);\r
637                         //done:\r
638                         break;\r
639                 case OP_OR:\r
640                         //test floats properly, so we don't get confused with -0.0\r
641 \r
642                         //flds  glob[A]\r
643                         EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].a);\r
644                         //fcomps        nullfloat\r
645                         EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);\r
646                         //fnstsw        %ax\r
647                         EmitByte(0xdf); EmitByte(0xe0);\r
648                         //test  $0x40,%ah\r
649                         EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);\r
650                         //je onetrue\r
651                         EmitByte(0x74); EmitByte(0x1f);\r
652 \r
653                         //flds  glob[B]\r
654                         EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].b);\r
655                         //fcomps        nullfloat\r
656                         EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);\r
657                         //fnstsw        %ax\r
658                         EmitByte(0xdf); EmitByte(0xe0);\r
659                         //test  $0x40,%ah\r
660                         EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);\r
661                         //je onetrue\r
662                         EmitByte(0x74); EmitByte(0x0c);\r
663 \r
664                         //mov float0,glob[C]\r
665                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);\r
666                         //jmp done\r
667                         EmitByte(0xeb); EmitByte(0x0a);\r
668 \r
669                         //onetrue:\r
670                         //mov float1,glob[C]\r
671                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);\r
672                         //done:\r
673                         break;\r
674 \r
675                 case OP_EQ_S:\r
676                 case OP_NE_S:\r
677                         //put a in ecx\r
678                         //put b in edi\r
679                         //mov a,%ecx\r
680                         EmitByte(0x8b); EmitByte(0x0d); EmitAdr(glob + op[i].a);\r
681                         //mov b,%edi\r
682                         EmitByte(0x8b); EmitByte(0x3d); EmitAdr(glob + op[i].b);\r
683 \r
684                         //early out if they're equal\r
685                         //cmp %ecx,%edi\r
686                         EmitByte(0x39); EmitByte(0xd1);\r
687                         //je _true\r
688                         EmitByte(0x74); EmitByte(0x68);\r
689 \r
690                         //if a is 0, check if b is ""\r
691                         //jecxz ais0\r
692                         EmitByte(0xe3); EmitByte(0x1a);\r
693 \r
694                         //if b is 0, check if a is ""\r
695                         //cmp $0,%edi\r
696                         EmitByte(0x83); EmitByte(0xff); EmitByte(0x00);\r
697                         //jne bnot0\r
698                         EmitByte(0x75); EmitByte(0x2a);\r
699                         {\r
700                                 //push a\r
701                                 EmitByte(0x51);\r
702                                 //push progfuncs\r
703                                 EmitByte(0x68); EmitAdr(progfuncs);\r
704                                 //call PR_StringToNative\r
705                                 EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);\r
706                                 //add $8,%esp\r
707                                 EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);\r
708                                 //cmpb $0,(%eax)\r
709                                 EmitByte(0x80); EmitByte(0x38); EmitByte(0x00);\r
710                                 //je _true\r
711                                 EmitByte(0x74); EmitByte(0x4b);\r
712                                 //jmp _false\r
713                                 EmitByte(0xeb); EmitByte(0x3d);\r
714 \r
715                                 //ais0:\r
716                                 {\r
717                                         //push edi\r
718                                         EmitByte(0x57);\r
719                                         //push progfuncs\r
720                                         EmitByte(0x68); EmitAdr(progfuncs);\r
721                                         //call PR_StringToNative\r
722                                         EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);\r
723                                         //add $8,%esp\r
724                                         EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);\r
725                                         //cmpb $0,(%eax)\r
726                                         EmitByte(0x80); EmitByte(0x38); EmitByte(0x00);\r
727                                         //je _true\r
728                                         EmitByte(0x74); EmitByte(0x36);\r
729                                         //jmp _false\r
730                                         EmitByte(0xeb); EmitByte(0x28);\r
731                                 }\r
732                         }\r
733                         //bnot0:\r
734 \r
735                         //push ecx\r
736                         EmitByte(0x51);\r
737                         //push progfuncs\r
738                         EmitByte(0x68); EmitAdr(progfuncs);\r
739                         //call PR_StringToNative\r
740                         EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);\r
741                         //push %eax\r
742                         EmitByte(0x50);\r
743 \r
744                         //push %edi\r
745                         EmitByte(0x57);\r
746                         //push progfuncs\r
747                         EmitByte(0x68); EmitAdr(progfuncs);\r
748                         //call PR_StringToNative\r
749                         EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);\r
750                         //add $8,%esp\r
751                         EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);\r
752 \r
753 \r
754                         //push %eax\r
755                         EmitByte(0x50);\r
756                         //call strcmp\r
757                         EmitByte(0xe8); EmitFOffset(strcmp,4);\r
758                         //add $16,%esp\r
759                         EmitByte(0x83); EmitByte(0xc4); EmitByte(0x10);\r
760                         //cmp $0,%eax\r
761                         EmitByte(0x83); EmitByte(0xf8); EmitByte(0x00);\r
762                         //je _true\r
763                         EmitByte(0x74); EmitByte(0x0c);\r
764 //_false:\r
765                         //mov 0.0f,c\r
766                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat((op[i].op == OP_NE_S)?1.0f:0.0f);\r
767                         //jmp done\r
768                         EmitByte(0xeb); EmitByte(0x0a);\r
769 //_true:\r
770                         //mov 1.0f,c\r
771                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat((op[i].op == OP_NE_S)?0.0f:1.0f);\r
772 //_done:\r
773                         break;\r
774 \r
775                 case OP_NOT_S:\r
776                         //mov A,%eax\r
777                         EmitByte(0xa1);EmitAdr(glob + op[i].a);\r
778                         //cmp $0,%eax\r
779                         EmitByte(0x83); EmitByte(0xf8); EmitByte(0x00);\r
780                         //je _true\r
781                         EmitByte(0x74); EmitByte(0x1f);\r
782                         //push %eax\r
783                         EmitByte(0x50);\r
784                         //push progfuncs\r
785                         EmitByte(0x68); EmitAdr(progfuncs);\r
786                         //call PR_StringToNative\r
787                         EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);\r
788                         //add $8,%esp\r
789                         EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);\r
790                         //cmpb $0,(%eax)\r
791                         EmitByte(0x80); EmitByte(0x38); EmitByte(0x00);\r
792                         //je _true\r
793                         EmitByte(0x74); EmitByte(0x0c);\r
794 //_false:\r
795                         //mov 0.0f,c\r
796                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);\r
797                         //jmp done\r
798                         EmitByte(0xeb); EmitByte(0x0a);\r
799 //_true:\r
800                         //mov 1.0f,c\r
801                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);\r
802 //_done:\r
803                         break;\r
804 \r
805                 case OP_ADD_V:\r
806                         //flds glob[A]\r
807                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);\r
808                         //fadds glob[B]\r
809                         EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b+0);\r
810                         //fstps glob[C]\r
811                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+0);\r
812 \r
813                         //flds glob[A]\r
814                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+1);\r
815                         //fadds glob[B]\r
816                         EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b+1);\r
817                         //fstps glob[C]\r
818                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+1);\r
819 \r
820                         //flds glob[A]\r
821                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+2);\r
822                         //fadds glob[B]\r
823                         EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b+2);\r
824                         //fstps glob[C]\r
825                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+2);\r
826                         break;\r
827                 case OP_SUB_V:\r
828                         //flds glob[A]\r
829                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);\r
830                         //fsubs glob[B]\r
831                         EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b+0);\r
832                         //fstps glob[C]\r
833                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+0);\r
834 \r
835                         //flds glob[A]\r
836                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+1);\r
837                         //fsubs glob[B]\r
838                         EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b+1);\r
839                         //fstps glob[C]\r
840                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+1);\r
841 \r
842                         //flds glob[A]\r
843                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+2);\r
844                         //fsubs glob[B]\r
845                         EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b+2);\r
846                         //fstps glob[C]\r
847                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+2);\r
848                         break;\r
849 \r
850                 case OP_MUL_V:\r
851                         //this is actually a dotproduct\r
852                         //flds glob[A]\r
853                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);\r
854                         //fmuls glob[B]\r
855                         EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b+0);\r
856 \r
857                         //flds glob[A]\r
858                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+1);\r
859                         //fmuls glob[B]\r
860                         EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b+1);\r
861 \r
862                         //flds glob[A]\r
863                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+2);\r
864                         //fmuls glob[B]\r
865                         EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b+2);\r
866 \r
867                         //faddp\r
868                         EmitByte(0xde);EmitByte(0xc1);\r
869                         //faddp\r
870                         EmitByte(0xde);EmitByte(0xc1);\r
871 \r
872                         //fstps glob[C]\r
873                         EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);\r
874                         break;\r
875 \r
876                 case OP_EQ_F:\r
877                 case OP_NE_F:\r
878                 case OP_LE:\r
879                 case OP_GE:\r
880                 case OP_LT:\r
881                 case OP_GT:\r
882                         //flds glob[A]\r
883                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);\r
884                         //flds glob[B]\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
890 \r
891                         //jcc _true\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
902                         else\r
903                                 EmitByte(0x74); //je\r
904                         EmitByte(0x0c);\r
905 //_false:\r
906                         //mov 0.0f,c\r
907                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);\r
908                         //jmp done\r
909                         EmitByte(0xeb); EmitByte(0x0a);\r
910 //_true:\r
911                         //mov 1.0f,c\r
912                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);\r
913 //_done:\r
914                         break;\r
915 \r
916                 case OP_MUL_FV:\r
917                 case OP_MUL_VF:\r
918                         //\r
919                         {\r
920                                 int v;\r
921                                 int f;\r
922                                 if (op[i].op == OP_MUL_FV)\r
923                                 {\r
924                                         f = op[i].a;\r
925                                         v = op[i].b;\r
926                                 }\r
927                                 else\r
928                                 {\r
929                                         v = op[i].a;\r
930                                         f = op[i].b;\r
931                                 }\r
932 \r
933                                 //flds glob[F]\r
934                                 EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + f);\r
935 \r
936                                 //flds glob[V0]\r
937                                 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + v+0);\r
938                                 //fmul st(1)\r
939                                 EmitByte(0xd8);EmitByte(0xc9);\r
940                                 //fstps glob[C]\r
941                                 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+0);\r
942 \r
943                                 //flds glob[V0]\r
944                                 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + v+1);\r
945                                 //fmul st(1)\r
946                                 EmitByte(0xd8);EmitByte(0xc9);\r
947                                 //fstps glob[C]\r
948                                 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+1);\r
949 \r
950                                 //flds glob[V0]\r
951                                 EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + v+2);\r
952                                 //fmul st(1)\r
953                                 EmitByte(0xd8);EmitByte(0xc9);\r
954                                 //fstps glob[C]\r
955                                 EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+2);\r
956 \r
957                                 //fstp %st(0)   (aka: pop)\r
958                                 EmitByte(0xdd);EmitByte(0xd8);\r
959                         }\r
960                         break;\r
961 \r
962                 case OP_STATE:\r
963                         //externs->stateop(progfuncs, OPA->_float, OPB->function);\r
964                         //push b\r
965                         EmitByte(0xff);EmitByte(0x35);EmitAdr(glob + op[i].b);\r
966                         //push a\r
967                         EmitByte(0xff);EmitByte(0x35);EmitAdr(glob + op[i].a);\r
968                         //push $progfuncs\r
969                         EmitByte(0x68); EmitAdr(progfuncs);\r
970                         //call externs->stateop\r
971                         EmitByte(0xe8); EmitFOffset(externs->stateop, 4);\r
972                         //add $12,%esp\r
973                         EmitByte(0x83); EmitByte(0xc4); EmitByte(0x0c);\r
974                         break;\r
975 #if 0\r
976                 case OP_NOT_V:\r
977                         //flds 0\r
978                         //flds glob[A+0]\r
979                         //fcomip %st(1),%st\r
980                         //jne _true\r
981                         //flds glob[A+1]\r
982                         //fcomip %st(1),%st\r
983                         //jne _true\r
984                         //flds glob[A+1]\r
985                         //fcomip %st(1),%st\r
986                         //jne _true\r
987                         //mov 1,C\r
988                         //jmp done\r
989                         //_true:\r
990                         //mov 0,C\r
991                         //done:\r
992                         break;\r
993 \r
994                 case OP_EQ_V:\r
995                         //flds glob[A]\r
996                         EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);\r
997                         //flds glob[B]\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
1003 \r
1004                         //jncc _true\r
1005                         if (op[i].op == OP_NE_V)\r
1006                                 EmitByte(0x74); //je\r
1007                         else\r
1008                                 EmitByte(0x75); //jne\r
1009                         EmitByte(0x0c);\r
1010 //_false0:\r
1011                         //mov 0.0f,c\r
1012                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);\r
1013                         //jmp done\r
1014                         EmitByte(0xeb); EmitByte(0x0a);\r
1015 \r
1016 \r
1017 //_true:\r
1018                         //mov 1.0f,c\r
1019                         EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);\r
1020 //_done:\r
1021                         break;\r
1022 \r
1023 \r
1024                 case OP_EQ_V:\r
1025                         EmitByte(0xcd);EmitByte(op[i].op);\r
1026                         printf("QCJIT: instruction %i is not implemented\n", op[i].op);\r
1027                         break;\r
1028 \r
1029                 case OP_NE_V:\r
1030                         EmitByte(0xcd);EmitByte(op[i].op);\r
1031                         printf("QCJIT: instruction %i is not implemented\n", op[i].op);\r
1032                         break;\r
1033 \r
1034                 case OP_NOT_V:\r
1035                         EmitByte(0xcd);EmitByte(op[i].op);\r
1036                         printf("QCJIT: instruction %i is not implemented\n", op[i].op);\r
1037                         break;\r
1038 #endif\r
1039                 default:\r
1040                         printf("QCJIT: Extended instruction set %i is not supported, not using jit.\n", op[i].op);\r
1041 \r
1042 \r
1043                         free(statementjumps);   //[MAX_STATEMENTS]\r
1044                         free(statementoffsets); //[MAX_STATEMENTS]\r
1045                         free(code);\r
1046                         statementoffsets = NULL;\r
1047                         return false;\r
1048                 }\r
1049         }\r
1050 \r
1051         FixupJumps();\r
1052 \r
1053 #ifdef _WIN32\r
1054         {\r
1055                 DWORD old;\r
1056 \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
1060         }\r
1061 #endif\r
1062 \r
1063 //      externs->WriteFile("jit.x86", code, codesize);\r
1064 \r
1065         return true;\r
1066 }\r
1067 \r
1068 void PR_EnterJIT(progfuncs_t *progfuncs, int statement)\r
1069 {\r
1070 #ifdef __GNUC__\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
1076         __asm {\r
1077                 pushad\r
1078                 mov eax,entry\r
1079                 mov ebx,edicttable\r
1080                 call eax\r
1081                 popad\r
1082         }\r
1083 #else\r
1084         #error "Sorry, no idea how to enter assembler safely for your compiler"\r
1085 #endif\r
1086 }\r
1087 #endif\r