1039 lines
29 KiB
C
1039 lines
29 KiB
C
|
/*
|
||
|
when I say JIT, I mean load time, not execution time.
|
||
|
|
||
|
notes:
|
||
|
qc jump offsets are all constants. we have no variable offset jumps (other than function calls/returns)
|
||
|
field remapping... fields are in place, and cannot be adjusted. if a field is not set to 0, its assumed to be a constant.
|
||
|
|
||
|
optimisations:
|
||
|
none at the moment...
|
||
|
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
|
||
|
it should also be possible to fold in eq+ifnot, so none of this silly storeing of floats in equality tests
|
||
|
|
||
|
eax - tmp
|
||
|
ebx - prinst->edicttable
|
||
|
ecx - tmp
|
||
|
edx - tmp
|
||
|
esi -
|
||
|
edi - tmp (because its preserved by subfunctions
|
||
|
ebp -
|
||
|
|
||
|
to use gas to provide binary opcodes:
|
||
|
vim -N blob.s && as blob.s && objdump.exe -d a.out
|
||
|
*/
|
||
|
|
||
|
#define PROGSUSED
|
||
|
#include "progsint.h"
|
||
|
|
||
|
#ifdef QCJIT
|
||
|
|
||
|
static float ta, tb, nullfloat=0;
|
||
|
|
||
|
unsigned int *statementjumps; //[MAX_STATEMENTS*2]
|
||
|
unsigned char **statementoffsets; //[MAX_STATEMENTS]
|
||
|
unsigned int numjumps;
|
||
|
unsigned char *code;
|
||
|
unsigned int codesize;
|
||
|
unsigned int jitstatements;
|
||
|
|
||
|
void EmitByte(unsigned char byte)
|
||
|
{
|
||
|
code[codesize++] = byte;
|
||
|
}
|
||
|
void Emit4Byte(unsigned int value)
|
||
|
{
|
||
|
code[codesize++] = (value>> 0)&0xff;
|
||
|
code[codesize++] = (value>> 8)&0xff;
|
||
|
code[codesize++] = (value>>16)&0xff;
|
||
|
code[codesize++] = (value>>24)&0xff;
|
||
|
}
|
||
|
void EmitAdr(void *value)
|
||
|
{
|
||
|
Emit4Byte((unsigned int)value);
|
||
|
}
|
||
|
void EmitFloat(float value)
|
||
|
{
|
||
|
union {float f; unsigned int i;} u;
|
||
|
u.f = value;
|
||
|
Emit4Byte(u.i);
|
||
|
}
|
||
|
void Emit2Byte(unsigned short value)
|
||
|
{
|
||
|
code[codesize++] = (value>> 0)&0xff;
|
||
|
code[codesize++] = (value>> 8)&0xff;
|
||
|
}
|
||
|
|
||
|
void EmitFOffset(void *func, int bias)
|
||
|
{
|
||
|
union {void *f; unsigned int i;} u;
|
||
|
u.f = func;
|
||
|
u.i -= (unsigned int)&code[codesize+bias];
|
||
|
Emit4Byte(u.i);
|
||
|
}
|
||
|
|
||
|
void Emit4ByteJump(int statementnum, int offset)
|
||
|
{
|
||
|
statementjumps[numjumps++] = codesize;
|
||
|
statementjumps[numjumps++] = statementnum;
|
||
|
statementjumps[numjumps++] = offset;
|
||
|
|
||
|
//the offset is filled in later
|
||
|
codesize += 4;
|
||
|
}
|
||
|
|
||
|
void FixupJumps(void)
|
||
|
{
|
||
|
unsigned int j;
|
||
|
unsigned char *codesrc;
|
||
|
unsigned char *codedst;
|
||
|
unsigned int offset;
|
||
|
|
||
|
unsigned int v;
|
||
|
|
||
|
for (j = 0; j < numjumps;)
|
||
|
{
|
||
|
v = statementjumps[j++];
|
||
|
codesrc = &code[v];
|
||
|
|
||
|
v = statementjumps[j++];
|
||
|
codedst = statementoffsets[v];
|
||
|
|
||
|
v = statementjumps[j++];
|
||
|
offset = (int)(codedst - (codesrc-v)); //3rd term because the jump is relative to the instruction start, not the instruction's offset
|
||
|
|
||
|
codesrc[0] = (offset>> 0)&0xff;
|
||
|
codesrc[1] = (offset>> 8)&0xff;
|
||
|
codesrc[2] = (offset>>16)&0xff;
|
||
|
codesrc[3] = (offset>>24)&0xff;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int PR_LeaveFunction (progfuncs_t *progfuncs);
|
||
|
int PR_EnterFunction (progfuncs_t *progfuncs, dfunction_t *f, int progsnum);
|
||
|
|
||
|
pbool PR_GenerateJit(progfuncs_t *progfuncs)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
dstatement16_t *op = (dstatement16_t*)current_progstate->statements;
|
||
|
unsigned int numstatements = current_progstate->progs->numstatements;
|
||
|
int *glob = (int*)current_progstate->globals;
|
||
|
|
||
|
if (current_progstate->numbuiltins)
|
||
|
return;
|
||
|
|
||
|
jitstatements = numstatements;
|
||
|
|
||
|
statementjumps = malloc(numstatements*12);
|
||
|
statementoffsets = malloc(numstatements*4);
|
||
|
code = malloc(numstatements*500);
|
||
|
|
||
|
numjumps = 0;
|
||
|
codesize = 0;
|
||
|
|
||
|
|
||
|
|
||
|
for (i = 0; i < numstatements; i++)
|
||
|
{
|
||
|
statementoffsets[i] = &code[codesize];
|
||
|
switch(op[i].op)
|
||
|
{
|
||
|
//jumps
|
||
|
case OP_IF:
|
||
|
//integer compare
|
||
|
//if a, goto b
|
||
|
|
||
|
//cmpl $0,glob[A]
|
||
|
EmitByte(0x83);EmitByte(0x3d);EmitAdr(glob + op[i].a);EmitByte(0x0);
|
||
|
//jnz B
|
||
|
EmitByte(0x0f);EmitByte(0x85);Emit4ByteJump(i + (signed short)op[i].b, -4);
|
||
|
break;
|
||
|
|
||
|
case OP_IFNOT:
|
||
|
//integer compare
|
||
|
//if !a, goto b
|
||
|
|
||
|
//cmpl $0,glob[A]
|
||
|
EmitByte(0x83);EmitByte(0x3d);EmitAdr(glob + op[i].a);EmitByte(0x0);
|
||
|
//jz B
|
||
|
EmitByte(0x0f);EmitByte(0x84);Emit4ByteJump(i + (signed short)op[i].b, -4);
|
||
|
break;
|
||
|
|
||
|
case OP_GOTO:
|
||
|
EmitByte(0xE9);Emit4ByteJump(i + (signed short)op[i].a, -4);
|
||
|
break;
|
||
|
|
||
|
//function returns
|
||
|
case OP_DONE:
|
||
|
case OP_RETURN:
|
||
|
//done and return are the same
|
||
|
|
||
|
//part 1: store A into OFS_RETURN
|
||
|
|
||
|
if (!op[i].a)
|
||
|
{
|
||
|
//assumption: anything that returns address 0 is a void or zero return.
|
||
|
//thus clear eax and copy that to the return vector.
|
||
|
EmitByte(0x31);EmitByte(0xc0);
|
||
|
EmitByte(0xa3);EmitAdr(glob + OFS_RETURN+0);
|
||
|
EmitByte(0xa3);EmitAdr(glob + OFS_RETURN+1);
|
||
|
EmitByte(0xa3);EmitAdr(glob + OFS_RETURN+2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//movl glob[A+0],eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
|
||
|
//movl glob[A+0],edx
|
||
|
EmitByte(0x8b);EmitByte(0x0d);EmitAdr(glob + op[i].a+1);
|
||
|
//movl glob[A+0],ecx
|
||
|
EmitByte(0x8b);EmitByte(0x15);EmitAdr(glob + op[i].a+2);
|
||
|
//movl eax, glob[OFS_RET+0]
|
||
|
EmitByte(0xa3);EmitAdr(glob + OFS_RETURN+0);
|
||
|
//movl edx, glob[OFS_RET+0]
|
||
|
EmitByte(0x89);EmitByte(0x15);EmitAdr(glob + OFS_RETURN+1);
|
||
|
//movl ecx, glob[OFS_RET+0]
|
||
|
EmitByte(0x89);EmitByte(0x15);EmitAdr(glob + OFS_RETURN+2);
|
||
|
}
|
||
|
|
||
|
//call leavefunction to get the return address
|
||
|
|
||
|
// pushl progfuncs
|
||
|
EmitByte(0x68);EmitAdr(progfuncs);
|
||
|
// call PR_LeaveFunction
|
||
|
EmitByte(0xe8);EmitFOffset(PR_LeaveFunction, 4);
|
||
|
// add $4,%esp
|
||
|
EmitByte(0x83);EmitByte(0xc4);EmitByte(0x04);
|
||
|
// movl pr_depth,%edx
|
||
|
EmitByte(0x8b);EmitByte(0x15);EmitAdr(&pr_depth);
|
||
|
// cmp prinst->exitdepth,%edx
|
||
|
EmitByte(0x3b);EmitByte(0x15);EmitAdr(&prinst->exitdepth);
|
||
|
// je returntoc
|
||
|
EmitByte(0x74);EmitByte(0x09);
|
||
|
// mov statementoffsets[%eax*4],%eax
|
||
|
EmitByte(0x8b);EmitByte(0x04);EmitByte(0x85);EmitAdr(statementoffsets+1);
|
||
|
// jmp eax
|
||
|
EmitByte(0xff);EmitByte(0xe0);
|
||
|
// returntoc:
|
||
|
// ret
|
||
|
EmitByte(0xc3);
|
||
|
break;
|
||
|
|
||
|
//function calls
|
||
|
case OP_CALL0:
|
||
|
case OP_CALL1:
|
||
|
case OP_CALL2:
|
||
|
case OP_CALL3:
|
||
|
case OP_CALL4:
|
||
|
case OP_CALL5:
|
||
|
case OP_CALL6:
|
||
|
case OP_CALL7:
|
||
|
case OP_CALL8:
|
||
|
//save the state in place the rest of the engine can cope with
|
||
|
//movl $i, pr_xstatement
|
||
|
EmitByte(0xc7);EmitByte(0x05);EmitAdr(&pr_xstatement);Emit4Byte(i);
|
||
|
//movl $(op[i].op-OP_CALL0), pr_argc
|
||
|
EmitByte(0xc7);EmitByte(0x05);EmitAdr(&pr_argc);Emit4Byte(op[i].op-OP_CALL0);
|
||
|
|
||
|
//figure out who we're calling, and what that involves
|
||
|
//%eax = glob[A]
|
||
|
EmitByte(0xa1); EmitAdr(glob + op[i].a);
|
||
|
//eax is now the func num
|
||
|
|
||
|
//mov %eax,%ecx
|
||
|
EmitByte(0x89); EmitByte(0xc1);
|
||
|
//shr $24,%ecx
|
||
|
EmitByte(0xc1); EmitByte(0xe9); EmitByte(0x18);
|
||
|
//ecx is now the progs num for the new func
|
||
|
|
||
|
//cmp %ecx,pr_typecurrent
|
||
|
EmitByte(0x39); EmitByte(0x0d); EmitAdr(&pr_typecurrent);
|
||
|
//je sameprogs
|
||
|
EmitByte(0x74); EmitByte(0x3);
|
||
|
{
|
||
|
//can't handle switching progs
|
||
|
|
||
|
//FIXME: recurse though PR_ExecuteProgram
|
||
|
//push eax
|
||
|
//push progfuncs
|
||
|
//call PR_ExecuteProgram
|
||
|
//add $8,%esp
|
||
|
//remember to change the je above
|
||
|
|
||
|
//err... exit depth? no idea
|
||
|
EmitByte(0xcd);EmitByte(op[i].op);
|
||
|
|
||
|
|
||
|
//ret
|
||
|
EmitByte(0xc3);
|
||
|
}
|
||
|
//sameprogs:
|
||
|
|
||
|
//andl $0x00ffffff, %eax
|
||
|
EmitByte(0x25);Emit4Byte(0x00ffffff);
|
||
|
|
||
|
//mov $sizeof(dfunction_t),%edx
|
||
|
EmitByte(0xba);Emit4Byte(sizeof(dfunction_t));
|
||
|
//mul %edx
|
||
|
EmitByte(0xf7); EmitByte(0xe2);
|
||
|
//add pr_functions,%eax
|
||
|
EmitByte(0x05); EmitAdr(pr_functions);
|
||
|
|
||
|
//eax is now the dfunction_t to be called
|
||
|
//edx is clobbered.
|
||
|
|
||
|
//mov (%eax),%edx
|
||
|
EmitByte(0x8b);EmitByte(0x10);
|
||
|
//edx is now the first statement number
|
||
|
//cmp $0,%edx
|
||
|
EmitByte(0x83);EmitByte(0xfa);EmitByte(0x00);
|
||
|
//jl isabuiltin
|
||
|
EmitByte(0x7c);EmitByte(22);
|
||
|
|
||
|
{
|
||
|
//push %ecx
|
||
|
EmitByte(0x51);
|
||
|
//push %eax
|
||
|
EmitByte(0x50);
|
||
|
//pushl progfuncs
|
||
|
EmitByte(0x68);EmitAdr(progfuncs);
|
||
|
//call PR_EnterFunction
|
||
|
EmitByte(0xe8);EmitFOffset(PR_EnterFunction, 4);
|
||
|
//sub $12,%esp
|
||
|
EmitByte(0x83);EmitByte(0xc4);EmitByte(0xc);
|
||
|
//eax is now the next statement number (first of the new function, usually equal to ecx, but not always)
|
||
|
|
||
|
//jmp statementoffsets[%eax*4]
|
||
|
EmitByte(0xff);EmitByte(0x24);EmitByte(0x85);EmitAdr(statementoffsets+1);
|
||
|
}
|
||
|
//isabuiltin:
|
||
|
|
||
|
|
||
|
//push current_progstate->globals
|
||
|
EmitByte(0x68);EmitAdr(current_progstate->globals);
|
||
|
//push progfuncs
|
||
|
EmitByte(0x68);EmitAdr(progfuncs);
|
||
|
//neg %edx
|
||
|
EmitByte(0xf7);EmitByte(0xda);
|
||
|
//call externs->globalbuiltins[%edx,4]
|
||
|
//FIXME: make sure this dereferences
|
||
|
EmitByte(0xff);EmitByte(0x14);EmitByte(0x95);EmitAdr(externs->globalbuiltins);
|
||
|
//add $8,%esp
|
||
|
EmitByte(0x83);EmitByte(0xc4);EmitByte(0x8);
|
||
|
|
||
|
//but that builtin might have been Abort()
|
||
|
|
||
|
//mov prinst->continuestatement,%eax
|
||
|
EmitByte(0xa1);EmitAdr(&prinst->continuestatement);
|
||
|
//eax is now prinst->continuestatement
|
||
|
|
||
|
//cmp $-1,%eax
|
||
|
EmitByte(0x83);EmitByte(0xf8);EmitByte(0xff);
|
||
|
//je donebuiltincall
|
||
|
EmitByte(0x74);EmitByte(10+8);
|
||
|
{
|
||
|
EmitByte(0xcc);
|
||
|
//jmp statementoffsets[%eax*4]
|
||
|
EmitByte(0xff);EmitByte(0x24);EmitByte(0x85);EmitAdr(statementoffsets+1);
|
||
|
|
||
|
//mov $-1,prinst->continuestatement
|
||
|
EmitByte(0xc7);EmitByte(0x05);EmitAdr(&prinst->continuestatement+1);Emit4Byte((unsigned int)-1);
|
||
|
}
|
||
|
//donebuiltincall:
|
||
|
break;
|
||
|
|
||
|
case OP_MUL_F:
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
|
||
|
//fmuls glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
|
||
|
break;
|
||
|
case OP_DIV_F:
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
|
||
|
//fdivs glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x35);EmitAdr(glob + op[i].b);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
|
||
|
break;
|
||
|
case OP_ADD_F:
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
|
||
|
//fadds glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
|
||
|
break;
|
||
|
case OP_SUB_F:
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
|
||
|
//fsubs glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
|
||
|
break;
|
||
|
|
||
|
case OP_NOT_F:
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
|
||
|
//fldz
|
||
|
EmitByte(0xd9);EmitByte(0xee);
|
||
|
//fnstsw %ax
|
||
|
EmitByte(0xdf);EmitByte(0xe0);
|
||
|
//testb 0x40,%ah
|
||
|
EmitByte(0xf6);EmitByte(0xc4);EmitByte(0x40);
|
||
|
//je noteq
|
||
|
EmitByte(0x74);EmitByte(0x0c);
|
||
|
//movl 1.0f,glob[C]
|
||
|
EmitByte(0xc7);EmitByte(0x05);EmitAdr(glob + op[i].c);EmitFloat(0.0f);
|
||
|
//jmp end
|
||
|
EmitByte(0xeb);EmitByte(0x0a);
|
||
|
//noteq:
|
||
|
//movl 0.0f,glob[C]
|
||
|
EmitByte(0xc7);EmitByte(0x05);EmitAdr(glob + op[i].c);EmitFloat(1.0f);
|
||
|
//end:
|
||
|
break;
|
||
|
|
||
|
case OP_STORE_F:
|
||
|
case OP_STORE_S:
|
||
|
case OP_STORE_ENT:
|
||
|
case OP_STORE_FLD:
|
||
|
case OP_STORE_FNC:
|
||
|
//movl glob[A],eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a);
|
||
|
//movl eax,glob[B]
|
||
|
EmitByte(0xa3);EmitAdr(glob + op[i].b);
|
||
|
break;
|
||
|
|
||
|
case OP_STORE_V:
|
||
|
//movl glob[A+0],eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
|
||
|
//movl glob[A+1],edx
|
||
|
EmitByte(0x8b);EmitByte(0x0d);EmitAdr(glob + op[i].a+1);
|
||
|
//movl glob[A+2],ecx
|
||
|
EmitByte(0x8b);EmitByte(0x15);EmitAdr(glob + op[i].a+2);
|
||
|
|
||
|
//movl eax, glob[B+0]
|
||
|
EmitByte(0xa3);EmitAdr(glob + op[i].b+0);
|
||
|
//movl edx, glob[B+1]
|
||
|
EmitByte(0x89);EmitByte(0x15);EmitAdr(glob + op[i].b+1);
|
||
|
//movl ecx, glob[B+2]
|
||
|
EmitByte(0x89);EmitByte(0x15);EmitAdr(glob + op[i].b+2);
|
||
|
break;
|
||
|
|
||
|
case OP_LOAD_F:
|
||
|
case OP_LOAD_S:
|
||
|
case OP_LOAD_ENT:
|
||
|
case OP_LOAD_FLD:
|
||
|
case OP_LOAD_FNC:
|
||
|
case OP_LOAD_V:
|
||
|
//a is the ent number, b is the field
|
||
|
//c is the dest
|
||
|
|
||
|
//movl glob[A+0],eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a);
|
||
|
//mov glob[B],ecx
|
||
|
EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);
|
||
|
//FIXME: bound eax (ent number)
|
||
|
//FIXME: bound ecx (field index)
|
||
|
//mov (ebx,eax,4).%eax
|
||
|
EmitByte(0x8b); EmitByte(0x04); EmitByte(0x83);
|
||
|
//eax is now an edictrun_t
|
||
|
//mov fields(,%eax,4),%edx
|
||
|
EmitByte(0x8b);EmitByte(0x50);EmitByte((int)&((edictrun_t*)NULL)->fields);
|
||
|
//edx is now the field array for that ent
|
||
|
|
||
|
//mov fieldajust(%edx,%ecx,4),%eax //offset = progfuncs->fieldadjust
|
||
|
EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(progfuncs->fieldadjust*4);
|
||
|
//mov edx,glob[C]
|
||
|
EmitByte(0xa3);EmitAdr(glob + op[i].c);
|
||
|
|
||
|
if (op[i].op == OP_LOAD_V)
|
||
|
{
|
||
|
//mov fieldajust+4(%edx,%ecx,4),%eax //offset = progfuncs->fieldadjust
|
||
|
EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(4+progfuncs->fieldadjust*4);
|
||
|
//mov edx,glob[C+1]
|
||
|
EmitByte(0xa3);EmitAdr(glob + op[i].c+1);
|
||
|
|
||
|
//mov fieldajust+8(%edx,%ecx,4),%eax //offset = progfuncs->fieldadjust
|
||
|
EmitByte(0x8b); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(4+progfuncs->fieldadjust*4);
|
||
|
//mov edx,glob[C+1]
|
||
|
EmitByte(0xa3);EmitAdr(glob + op[i].c+2);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OP_ADDRESS:
|
||
|
//a is the ent number, b is the field
|
||
|
//c is the dest
|
||
|
|
||
|
//movl glob[A+0],eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a);
|
||
|
//mov glob[B],ecx
|
||
|
EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);
|
||
|
//FIXME: bound eax (ent number)
|
||
|
//FIXME: bound ecx (field index)
|
||
|
//mov (ebx,eax,4).%eax
|
||
|
EmitByte(0x8b); EmitByte(0x04); EmitByte(0x83);
|
||
|
//eax is now an edictrun_t
|
||
|
//mov fields(,%eax,4),%edx
|
||
|
EmitByte(0x8b);EmitByte(0x50);EmitByte((int)&((edictrun_t*)NULL)->fields);
|
||
|
//edx is now the field array for that ent
|
||
|
//mov fieldajust(%edx,%ecx,4),%eax //offset = progfuncs->fieldadjust
|
||
|
//EmitByte(0x8d); EmitByte(0x84); EmitByte(0x8a); EmitByte(progfuncs->fieldadjust*4);
|
||
|
EmitByte(0x8d); EmitByte(0x84); EmitByte(0x8a); Emit4Byte(progfuncs->fieldadjust*4);
|
||
|
//mov edx,glob[C]
|
||
|
EmitByte(0xa3);EmitAdr(glob + op[i].c);
|
||
|
break;
|
||
|
|
||
|
case OP_STOREP_F:
|
||
|
case OP_STOREP_S:
|
||
|
case OP_STOREP_ENT:
|
||
|
case OP_STOREP_FLD:
|
||
|
case OP_STOREP_FNC:
|
||
|
//movl glob[A],eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a);
|
||
|
//mov glob[B],ecx
|
||
|
EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);
|
||
|
//mov %eax,(%ecx)
|
||
|
EmitByte(0x89);EmitByte(0x01);
|
||
|
break;
|
||
|
|
||
|
case OP_STOREP_V:
|
||
|
//mov glob[B],ecx
|
||
|
EmitByte(0x8b); EmitByte(0x0d);EmitAdr(glob + op[i].b);
|
||
|
//movl glob[A],eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
|
||
|
//mov %eax,0(%ecx)
|
||
|
EmitByte(0x89);EmitByte(0x01);
|
||
|
//movl glob[A],eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
|
||
|
//mov %eax,4(%ecx)
|
||
|
EmitByte(0x89);EmitByte(0x41);EmitByte(0x04);
|
||
|
//movl glob[A],eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a+0);
|
||
|
//mov %eax,8(%ecx)
|
||
|
EmitByte(0x89);EmitByte(0x41);EmitByte(0x08);
|
||
|
break;
|
||
|
|
||
|
case OP_EQ_E:
|
||
|
case OP_EQ_FNC:
|
||
|
//integer equality
|
||
|
//movl glob[A],%eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a);
|
||
|
//cmp glob[B],%eax
|
||
|
EmitByte(0x3b); EmitByte(0x0f); EmitAdr(glob + op[i].b);
|
||
|
//je 12
|
||
|
EmitByte(0x74);EmitByte(0x0c);
|
||
|
//mov 0.0f,glob[C]
|
||
|
EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(0.0f);
|
||
|
//jmp 10
|
||
|
EmitByte(0xeb);EmitByte(0x0a);
|
||
|
//mov 1.0f,glob[C]
|
||
|
EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(1.0f);
|
||
|
break;
|
||
|
|
||
|
case OP_NE_E:
|
||
|
case OP_NE_FNC:
|
||
|
//integer equality
|
||
|
//movl glob[A],%eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a);
|
||
|
//cmp glob[B],%eax
|
||
|
EmitByte(0x3b); EmitByte(0x0f); EmitAdr(glob + op[i].b);
|
||
|
//je 12
|
||
|
EmitByte(0x74);EmitByte(0x0c);
|
||
|
//mov 0.0f,glob[C]
|
||
|
EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(1.0f);
|
||
|
//jmp 10
|
||
|
EmitByte(0xeb);EmitByte(0x0a);
|
||
|
//mov 1.0f,glob[C]
|
||
|
EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(0.0f);
|
||
|
break;
|
||
|
|
||
|
case OP_NOT_ENT:
|
||
|
case OP_NOT_FNC:
|
||
|
//cmp glob[B],%eax
|
||
|
EmitByte(0x8c); EmitByte(0x3d); EmitAdr(glob + op[i].a);EmitByte(0x00);
|
||
|
//je 12
|
||
|
EmitByte(0x74);EmitByte(0x0c);
|
||
|
//mov 0.0f,glob[C]
|
||
|
EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(0.0f);
|
||
|
//jmp 10
|
||
|
EmitByte(0xeb);EmitByte(0x0a);
|
||
|
//mov 1.0f,glob[C]
|
||
|
EmitByte(0xc7);EmitByte(0x05); EmitAdr(glob + op[i].a);EmitFloat(1.0f);
|
||
|
break;
|
||
|
|
||
|
case OP_BITOR: //floats...
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].a);
|
||
|
//flds glob[B]
|
||
|
EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].b);
|
||
|
//fistp tb
|
||
|
EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&tb);
|
||
|
//fistp ta
|
||
|
EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&ta);
|
||
|
//mov ta,%eax
|
||
|
EmitByte(0xa1); EmitAdr(&ta);
|
||
|
//and tb,%eax
|
||
|
EmitByte(0x09); EmitByte(0x05);EmitAdr(&tb);
|
||
|
//fild tb
|
||
|
EmitByte(0xdf); EmitByte(0x05);EmitAdr(&tb);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9); EmitByte(0x1d);EmitAdr(glob + op[i].c);
|
||
|
break;
|
||
|
|
||
|
case OP_BITAND:
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].a);
|
||
|
//flds glob[B]
|
||
|
EmitByte(0xd9); EmitByte(0x05);EmitAdr(glob + op[i].b);
|
||
|
//fistp tb
|
||
|
EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&tb);
|
||
|
//fistp ta
|
||
|
EmitByte(0xdf); EmitByte(0x1d);EmitAdr(&ta);
|
||
|
//mov ta,%eax
|
||
|
EmitByte(0xa1); EmitAdr(&ta);
|
||
|
//and tb,%eax
|
||
|
EmitByte(0x21); EmitByte(0x05);EmitAdr(&tb);
|
||
|
//fild tb
|
||
|
EmitByte(0xdf); EmitByte(0x05);EmitAdr(&tb);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9); EmitByte(0x1d);EmitAdr(glob + op[i].c);
|
||
|
break;
|
||
|
|
||
|
case OP_AND:
|
||
|
//test floats properly, so we don't get confused with -0.0
|
||
|
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].a);
|
||
|
//fcomps nullfloat
|
||
|
EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);
|
||
|
//fnstsw %ax
|
||
|
EmitByte(0xdf); EmitByte(0xe0);
|
||
|
//test $0x40,%ah
|
||
|
EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);
|
||
|
//je onefalse
|
||
|
EmitByte(0x75); EmitByte(0x1f);
|
||
|
|
||
|
//flds glob[B]
|
||
|
EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].b);
|
||
|
//fcomps nullfloat
|
||
|
EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);
|
||
|
//fnstsw %ax
|
||
|
EmitByte(0xdf); EmitByte(0xe0);
|
||
|
//test $0x40,%ah
|
||
|
EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);
|
||
|
//jne onefalse
|
||
|
EmitByte(0x75); EmitByte(0x0c);
|
||
|
|
||
|
//mov float0,glob[C]
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);
|
||
|
//jmp done
|
||
|
EmitByte(0xeb); EmitByte(0x0a);
|
||
|
|
||
|
//onefalse:
|
||
|
//mov float1,glob[C]
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);
|
||
|
//done:
|
||
|
break;
|
||
|
case OP_OR:
|
||
|
//test floats properly, so we don't get confused with -0.0
|
||
|
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].a);
|
||
|
//fcomps nullfloat
|
||
|
EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);
|
||
|
//fnstsw %ax
|
||
|
EmitByte(0xdf); EmitByte(0xe0);
|
||
|
//test $0x40,%ah
|
||
|
EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);
|
||
|
//je onetrue
|
||
|
EmitByte(0x74); EmitByte(0x1f);
|
||
|
|
||
|
//flds glob[B]
|
||
|
EmitByte(0xd9); EmitByte(0x05); EmitAdr(glob + op[i].b);
|
||
|
//fcomps nullfloat
|
||
|
EmitByte(0xd8); EmitByte(0x1d); EmitAdr(&nullfloat);
|
||
|
//fnstsw %ax
|
||
|
EmitByte(0xdf); EmitByte(0xe0);
|
||
|
//test $0x40,%ah
|
||
|
EmitByte(0xf6); EmitByte(0xc4);EmitByte(0x40);
|
||
|
//je onetrue
|
||
|
EmitByte(0x74); EmitByte(0x0c);
|
||
|
|
||
|
//mov float0,glob[C]
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);
|
||
|
//jmp done
|
||
|
EmitByte(0xeb); EmitByte(0x0a);
|
||
|
|
||
|
//onetrue:
|
||
|
//mov float1,glob[C]
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);
|
||
|
//done:
|
||
|
break;
|
||
|
|
||
|
case OP_EQ_S:
|
||
|
case OP_NE_S:
|
||
|
//put a in ecx
|
||
|
//put b in edi
|
||
|
//mov a,%ecx
|
||
|
EmitByte(0x8b); EmitByte(0x0d); EmitAdr(glob + op[i].a);
|
||
|
//mov b,%edi
|
||
|
EmitByte(0x8b); EmitByte(0x3d); EmitAdr(glob + op[i].b);
|
||
|
|
||
|
//early out if they're equal
|
||
|
//cmp %ecx,%edi
|
||
|
EmitByte(0x39); EmitByte(0xd1);
|
||
|
//je _true
|
||
|
EmitByte(0x74); EmitByte(0x68);
|
||
|
|
||
|
//if a is 0, check if b is ""
|
||
|
//jecxz ais0
|
||
|
EmitByte(0xe3); EmitByte(0x1a);
|
||
|
|
||
|
//if b is 0, check if a is ""
|
||
|
//cmp $0,%edi
|
||
|
EmitByte(0x83); EmitByte(0xff); EmitByte(0x00);
|
||
|
//jne bnot0
|
||
|
EmitByte(0x75); EmitByte(0x2a);
|
||
|
{
|
||
|
//push a
|
||
|
EmitByte(0x51);
|
||
|
//push progfuncs
|
||
|
EmitByte(0x68); EmitAdr(progfuncs);
|
||
|
//call PR_StringToNative
|
||
|
EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
|
||
|
//add $8,%esp
|
||
|
EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);
|
||
|
//cmpb $0,(%eax)
|
||
|
EmitByte(0x80); EmitByte(0x38); EmitByte(0x00);
|
||
|
//je _true
|
||
|
EmitByte(0x74); EmitByte(0x4b);
|
||
|
//jmp _false
|
||
|
EmitByte(0xeb); EmitByte(0x3d);
|
||
|
|
||
|
//ais0:
|
||
|
{
|
||
|
//push edi
|
||
|
EmitByte(0x57);
|
||
|
//push progfuncs
|
||
|
EmitByte(0x68); EmitAdr(progfuncs);
|
||
|
//call PR_StringToNative
|
||
|
EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
|
||
|
//add $8,%esp
|
||
|
EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);
|
||
|
//cmpb $0,(%eax)
|
||
|
EmitByte(0x80); EmitByte(0x38); EmitByte(0x00);
|
||
|
//je _true
|
||
|
EmitByte(0x74); EmitByte(0x36);
|
||
|
//jmp _false
|
||
|
EmitByte(0xeb); EmitByte(0x28);
|
||
|
}
|
||
|
}
|
||
|
//bnot0:
|
||
|
|
||
|
//push ecx
|
||
|
EmitByte(0x51);
|
||
|
//push progfuncs
|
||
|
EmitByte(0x68); EmitAdr(progfuncs);
|
||
|
//call PR_StringToNative
|
||
|
EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
|
||
|
//push %eax
|
||
|
EmitByte(0x50);
|
||
|
|
||
|
//push %edi
|
||
|
EmitByte(0x57);
|
||
|
//push progfuncs
|
||
|
EmitByte(0x68); EmitAdr(progfuncs);
|
||
|
//call PR_StringToNative
|
||
|
EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
|
||
|
//add $8,%esp
|
||
|
EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);
|
||
|
|
||
|
|
||
|
//push %eax
|
||
|
EmitByte(0x50);
|
||
|
//call strcmp
|
||
|
EmitByte(0xe8); EmitFOffset(strcmp,4);
|
||
|
//add $16,%esp
|
||
|
EmitByte(0x83); EmitByte(0xc4); EmitByte(0x10);
|
||
|
//cmp $0,%eax
|
||
|
EmitByte(0x83); EmitByte(0xf8); EmitByte(0x00);
|
||
|
//je _true
|
||
|
EmitByte(0x74); EmitByte(0x0c);
|
||
|
//_false:
|
||
|
//mov 0.0f,c
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat((op[i].op == OP_NE_S)?1.0f:0.0f);
|
||
|
//jmp done
|
||
|
EmitByte(0xeb); EmitByte(0x0a);
|
||
|
//_true:
|
||
|
//mov 1.0f,c
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat((op[i].op == OP_NE_S)?0.0f:1.0f);
|
||
|
//_done:
|
||
|
break;
|
||
|
|
||
|
case OP_NOT_S:
|
||
|
//mov A,%eax
|
||
|
EmitByte(0xa1);EmitAdr(glob + op[i].a);
|
||
|
//cmp $0,%eax
|
||
|
EmitByte(0x83); EmitByte(0xf8); EmitByte(0x00);
|
||
|
//je _true
|
||
|
EmitByte(0x74); EmitByte(0x1f);
|
||
|
//push %eax
|
||
|
EmitByte(0x50);
|
||
|
//push progfuncs
|
||
|
EmitByte(0x68); EmitAdr(progfuncs);
|
||
|
//call PR_StringToNative
|
||
|
EmitByte(0xe8); EmitFOffset(PR_StringToNative,4);
|
||
|
//add $8,%esp
|
||
|
EmitByte(0x83); EmitByte(0xc4); EmitByte(0x08);
|
||
|
//cmpb $0,(%eax)
|
||
|
EmitByte(0x80); EmitByte(0x38); EmitByte(0x00);
|
||
|
//je _true
|
||
|
EmitByte(0x74); EmitByte(0x0c);
|
||
|
//_false:
|
||
|
//mov 0.0f,c
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);
|
||
|
//jmp done
|
||
|
EmitByte(0xeb); EmitByte(0x0a);
|
||
|
//_true:
|
||
|
//mov 1.0f,c
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);
|
||
|
//_done:
|
||
|
break;
|
||
|
|
||
|
case OP_ADD_V:
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);
|
||
|
//fadds glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b+0);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+0);
|
||
|
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+1);
|
||
|
//fadds glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b+1);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+1);
|
||
|
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+2);
|
||
|
//fadds glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x05);EmitAdr(glob + op[i].b+2);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+2);
|
||
|
break;
|
||
|
case OP_SUB_V:
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);
|
||
|
//fsubs glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b+0);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+0);
|
||
|
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+1);
|
||
|
//fsubs glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b+1);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+1);
|
||
|
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+2);
|
||
|
//fsubs glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x25);EmitAdr(glob + op[i].b+2);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+2);
|
||
|
break;
|
||
|
|
||
|
case OP_MUL_V:
|
||
|
//this is actually a dotproduct
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+0);
|
||
|
//fmuls glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b+0);
|
||
|
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+1);
|
||
|
//fmuls glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b+1);
|
||
|
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a+2);
|
||
|
//fmuls glob[B]
|
||
|
EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + op[i].b+2);
|
||
|
|
||
|
//faddp
|
||
|
EmitByte(0xde);EmitByte(0xc1);
|
||
|
//faddp
|
||
|
EmitByte(0xde);EmitByte(0xc1);
|
||
|
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c);
|
||
|
break;
|
||
|
|
||
|
case OP_EQ_F:
|
||
|
case OP_NE_F:
|
||
|
case OP_LE:
|
||
|
case OP_GE:
|
||
|
case OP_LT:
|
||
|
case OP_GT:
|
||
|
//flds glob[A]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].a);
|
||
|
//flds glob[B]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + op[i].b);
|
||
|
//fcomip %st(1),%st
|
||
|
EmitByte(0xdf);EmitByte(0xe9);
|
||
|
//fstp %st(0) (aka: pop)
|
||
|
EmitByte(0xdd);EmitByte(0xd8);
|
||
|
|
||
|
//jcc _true
|
||
|
if (op[i].op == OP_LE)
|
||
|
EmitByte(0x7e); //jle
|
||
|
else if (op[i].op == OP_GE)
|
||
|
EmitByte(0x7d); //jge
|
||
|
else if (op[i].op == OP_LT)
|
||
|
EmitByte(0x7c); //jl
|
||
|
else if (op[i].op == OP_GT)
|
||
|
EmitByte(0x7f); //jg
|
||
|
else if (op[i].op == OP_NE_F)
|
||
|
EmitByte(0x75); //jne
|
||
|
else
|
||
|
EmitByte(0x74); //je
|
||
|
EmitByte(0x0c);
|
||
|
//_false:
|
||
|
//mov 0.0f,c
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(0.0f);
|
||
|
//jmp done
|
||
|
EmitByte(0xeb); EmitByte(0x0a);
|
||
|
//_true:
|
||
|
//mov 1.0f,c
|
||
|
EmitByte(0xc7); EmitByte(0x05); EmitAdr(glob + op[i].c); EmitFloat(1.0f);
|
||
|
//_done:
|
||
|
break;
|
||
|
|
||
|
case OP_MUL_FV:
|
||
|
case OP_MUL_VF:
|
||
|
//
|
||
|
{
|
||
|
int v;
|
||
|
int f;
|
||
|
if (op[i].op == OP_MUL_FV)
|
||
|
{
|
||
|
f = op[i].a;
|
||
|
v = op[i].b;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
v = op[i].a;
|
||
|
f = op[i].b;
|
||
|
}
|
||
|
|
||
|
//flds glob[F]
|
||
|
EmitByte(0xd9);EmitByte(0x05);EmitAdr(glob + f);
|
||
|
|
||
|
//flds glob[V0]
|
||
|
EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + v+0);
|
||
|
//fmul st(1)
|
||
|
EmitByte(0xd8);EmitByte(0xc9);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+0);
|
||
|
|
||
|
//flds glob[V0]
|
||
|
EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + v+1);
|
||
|
//fmul st(1)
|
||
|
EmitByte(0xd8);EmitByte(0xc9);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+1);
|
||
|
|
||
|
//flds glob[V0]
|
||
|
EmitByte(0xd8);EmitByte(0x0d);EmitAdr(glob + v+2);
|
||
|
//fmul st(1)
|
||
|
EmitByte(0xd8);EmitByte(0xc9);
|
||
|
//fstps glob[C]
|
||
|
EmitByte(0xd9);EmitByte(0x1d);EmitAdr(glob + op[i].c+2);
|
||
|
|
||
|
//fstp %st(0) (aka: pop)
|
||
|
EmitByte(0xdd);EmitByte(0xd8);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OP_STATE:
|
||
|
//externs->stateop(progfuncs, OPA->_float, OPB->function);
|
||
|
//push b
|
||
|
EmitByte(0xff);EmitByte(0x35);EmitAdr(glob + op[i].b);
|
||
|
//push a
|
||
|
EmitByte(0xff);EmitByte(0x35);EmitAdr(glob + op[i].a);
|
||
|
//push $progfuncs
|
||
|
EmitByte(0x68); EmitAdr(progfuncs);
|
||
|
//call externs->stateop
|
||
|
EmitByte(0xe8); EmitFOffset(externs->stateop, 4);
|
||
|
//add $12,%esp
|
||
|
EmitByte(0x83); EmitByte(0xc4); EmitByte(0x0c);
|
||
|
break;
|
||
|
/*
|
||
|
case OP_EQ_V:
|
||
|
EmitByte(0xcd);EmitByte(op[i].op);
|
||
|
printf("QCJIT: instruction %i is not implemented\n", op[i].op);
|
||
|
break;
|
||
|
|
||
|
case OP_NE_V:
|
||
|
EmitByte(0xcd);EmitByte(op[i].op);
|
||
|
printf("QCJIT: instruction %i is not implemented\n", op[i].op);
|
||
|
break;
|
||
|
|
||
|
case OP_NOT_V:
|
||
|
EmitByte(0xcd);EmitByte(op[i].op);
|
||
|
printf("QCJIT: instruction %i is not implemented\n", op[i].op);
|
||
|
break;
|
||
|
*/
|
||
|
default:
|
||
|
printf("QCJIT: Extended instruction set %i is not supported, not using jit.\n", op[i].op);
|
||
|
|
||
|
|
||
|
free(statementjumps); //[MAX_STATEMENTS]
|
||
|
free(statementoffsets); //[MAX_STATEMENTS]
|
||
|
free(code);
|
||
|
statementoffsets = NULL;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FixupJumps();
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
{
|
||
|
DWORD old;
|
||
|
|
||
|
//this memory is on the heap.
|
||
|
//this means that we must maintain read/write protection, or libc will crash us
|
||
|
VirtualProtect(code, codesize, PAGE_EXECUTE_READWRITE, &old);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// externs->WriteFile("jit.x86", code, codesize);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void PR_EnterJIT(progfuncs_t *progfuncs, int statement)
|
||
|
{
|
||
|
#ifdef __GNUC__
|
||
|
//call, it clobbers pretty much everything.
|
||
|
asm("call %0" :: "r"(statementoffsets[statement+1]),"b"(prinst->edicttable):"cc","memory","eax","ecx","edx");
|
||
|
#elif defined(_MSC_VER)
|
||
|
void *entry = statementoffsets[statement+1];
|
||
|
void *edicttable = prinst->edicttable;
|
||
|
__asm {
|
||
|
pushad
|
||
|
mov eax,entry
|
||
|
mov ebx,edicttable
|
||
|
call eax
|
||
|
popad
|
||
|
}
|
||
|
#else
|
||
|
#error "Sorry, no idea how to enter assembler safely for your compiler"
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|