diff --git a/code/qcommon/vm_x86_64.c b/code/qcommon/vm_x86_64.c index 3a6eef19..bcbc5669 100644 --- a/code/qcommon/vm_x86_64.c +++ b/code/qcommon/vm_x86_64.c @@ -239,8 +239,23 @@ void emit(const char* fmt, ...) emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[iarg]); \ emit("jmpq *%%rax"); +#define CONST_OPTIMIZE +#ifdef CONST_OPTIMIZE +#define MAYBE_EMIT_CONST() \ + if (got_const) \ + { \ + got_const = 0; \ + vm->instructionPointers[instruction-1] = assembler_get_code_size(); \ + emit("addq $4, %%rsi"); \ + emit("movl $%d, 0(%%rsi)", const_value); \ + } +#else +#define MAYBE_EMIT_CONST() +#endif + // integer compare and jump #define IJ(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $8, %%rsi"); \ emit("movl 4(%%rsi), %%eax"); \ emit("cmpl 8(%%rsi), %%eax"); \ @@ -250,6 +265,7 @@ void emit(const char* fmt, ...) #ifdef USE_X87 #define FJ(bits, op) \ + MAYBE_EMIT_CONST(); \ emit("subq $8, %%rsi");\ emit("flds 4(%%rsi)");\ emit("fcomps 8(%%rsi)");\ @@ -262,6 +278,7 @@ void emit(const char* fmt, ...) #else #define FJ(x, y) #define XJ(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $8, %%rsi");\ emit("movss 4(%%rsi), %%xmm0");\ emit("ucomiss 8(%%rsi), %%xmm0");\ @@ -272,12 +289,14 @@ void emit(const char* fmt, ...) #endif #define SIMPLE(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $4, %%rsi"); \ emit("movl 4(%%rsi), %%eax"); \ emit(op " %%eax, 0(%%rsi)"); #ifdef USE_X87 #define FSIMPLE(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $4, %%rsi"); \ emit("flds 0(%%rsi)"); \ emit(op " 4(%%rsi)"); \ @@ -286,6 +305,7 @@ void emit(const char* fmt, ...) #else #define FSIMPLE(op) #define XSIMPLE(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $4, %%rsi"); \ emit("movss 0(%%rsi), %%xmm0"); \ emit(op " 4(%%rsi), %%xmm0"); \ @@ -293,6 +313,7 @@ void emit(const char* fmt, ...) #endif #define SHIFT(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $4, %%rsi"); \ emit("movl 4(%%rsi), %%ecx"); \ emit("movl 0(%%rsi), %%eax"); \ @@ -343,6 +364,12 @@ static void block_copy_vm(unsigned dest, unsigned src, unsigned count) memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count); } +static void eop(void) +{ + Com_Error(ERR_DROP, "end of program reached without return!\n"); + exit(1); +} + /* ================= VM_Compile @@ -364,6 +391,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { int pass; size_t compiledOfs = 0; + // const optimization + unsigned got_const = 0, const_value = 0; + gettimeofday(&tvstart, NULL); for (pass = 0; pass < 2; ++pass) { @@ -400,7 +430,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { vm->instructionPointers[instruction] = assembler_get_code_size(); /* store current instruction number in r15 for debugging */ -#if DEBUG_VM +#if DEBUG_VM0 emit("nop"); emit("movq $%d, %%r15", instruction); emit("nop"); @@ -434,20 +464,25 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { NOTIMPL(op); break; case OP_IGNORE: + MAYBE_EMIT_CONST(); emit("nop"); break; case OP_BREAK: + MAYBE_EMIT_CONST(); emit("int3"); break; case OP_ENTER: + MAYBE_EMIT_CONST(); emit("subl $%d, %%edi", iarg); RANGECHECK(edi); break; case OP_LEAVE: + MAYBE_EMIT_CONST(); emit("addl $%d, %%edi", iarg); // get rid of stack frame emit("ret"); break; case OP_CALL: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get instr from stack emit("subq $4, %%rsi"); emit("movl $%d, 0(%%r8, %%rdi, 1)", instruction+1); // save next instruction @@ -489,31 +524,43 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { neednilabel = 1; break; case OP_PUSH: + MAYBE_EMIT_CONST(); emit("addq $4, %%rsi"); break; case OP_POP: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); break; case OP_CONST: - if(code[pc] == OP_JUMP) { - CHECK_IARG; - } + MAYBE_EMIT_CONST(); +#ifdef CONST_OPTIMIZE + got_const = 1; + const_value = iarg; +#else emit("addq $4, %%rsi"); emit("movl $%d, 0(%%rsi)", iarg); +#endif break; case OP_LOCAL: + MAYBE_EMIT_CONST(); emit("movl %%edi, %%ebx"); emit("addl $%d,%%ebx", iarg); emit("addq $4, %%rsi"); emit("movl %%ebx, 0(%%rsi)"); break; case OP_JUMP: - emit("movl 0(%%rsi), %%eax"); // get instr from stack - emit("subq $4, %%rsi"); - emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); - emit("movl (%%rbx, %%rax, 4), %%eax"); // load new relative jump address - emit("addq %%r10, %%rax"); - emit("jmp *%%rax"); + if(got_const) { + iarg = const_value; + got_const = 0; + JMPIARG; + } else { + emit("movl 0(%%rsi), %%eax"); // get instr from stack + emit("subq $4, %%rsi"); + emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); + emit("movl (%%rbx, %%rax, 4), %%eax"); // load new relative jump address + emit("addq %%r10, %%rax"); + emit("jmp *%%rax"); + } break; case OP_EQ: IJ("jne"); @@ -552,6 +599,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { case OP_NEF: FJ(0x40, "jnz"); #ifndef USE_X87 + MAYBE_EMIT_CONST(); emit("subq $8, %%rsi"); emit("movss 4(%%rsi), %%xmm0"); emit("ucomiss 8(%%rsi), %%xmm0"); @@ -579,6 +627,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { XJ("jb"); break; case OP_LOAD1: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack RANGECHECK(eax); emit("movb 0(%%r8, %%rax, 1), %%al"); // deref into eax @@ -586,18 +635,21 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%eax, 0(%%rsi)"); // store on stack break; case OP_LOAD2: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack RANGECHECK(eax); emit("movw 0(%%r8, %%rax, 1), %%ax"); // deref into eax emit("movl %%eax, 0(%%rsi)"); // store on stack break; case OP_LOAD4: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack RANGECHECK(eax); // not a pointer!? emit("movl 0(%%r8, %%rax, 1), %%eax"); // deref into eax emit("movl %%eax, 0(%%rsi)"); // store on stack break; case OP_STORE1: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack emit("andq $255, %%rax"); emit("movl -4(%%rsi), %%ebx"); // get pointer from stack @@ -606,6 +658,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("subq $8, %%rsi"); break; case OP_STORE2: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack emit("movl -4(%%rsi), %%ebx"); // get pointer from stack RANGECHECK(ebx); @@ -613,6 +666,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("subq $8, %%rsi"); break; case OP_STORE4: + MAYBE_EMIT_CONST(); emit("movl -4(%%rsi), %%ebx"); // get pointer from stack RANGECHECK(ebx); emit("movl 0(%%rsi), %%ecx"); // get value from stack @@ -620,6 +674,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("subq $8, %%rsi"); break; case OP_ARG: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 4(%%rsi), %%eax"); // get value from stack emit("movl $0x%hhx, %%ebx", barg); @@ -629,6 +684,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { break; case OP_BLOCK_COPY: + MAYBE_EMIT_CONST(); emit("subq $8, %%rsi"); emit("push %%rsi"); emit("push %%rdi"); @@ -648,6 +704,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { break; case OP_SEX8: + MAYBE_EMIT_CONST(); emit("movw 0(%%rsi), %%ax"); emit("andq $255, %%rax"); emit("cbw"); @@ -655,11 +712,13 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%eax, 0(%%rsi)"); break; case OP_SEX16: + MAYBE_EMIT_CONST(); emit("movw 0(%%rsi), %%ax"); emit("cwde"); emit("movl %%eax, 0(%%rsi)"); break; case OP_NEGI: + MAYBE_EMIT_CONST(); emit("negl 0(%%rsi)"); break; case OP_ADD: @@ -669,6 +728,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { SIMPLE("subl"); break; case OP_DIVI: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("cdq"); @@ -676,6 +736,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%eax, 0(%%rsi)"); break; case OP_DIVU: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("xorq %%rdx, %%rdx"); @@ -683,6 +744,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%eax, 0(%%rsi)"); break; case OP_MODI: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("xorl %%edx, %%edx"); @@ -691,6 +753,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%edx, 0(%%rsi)"); break; case OP_MODU: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("xorl %%edx, %%edx"); @@ -698,12 +761,14 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%edx, 0(%%rsi)"); break; case OP_MULI: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("imull 4(%%rsi)"); emit("movl %%eax, 0(%%rsi)"); break; case OP_MULU: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("mull 4(%%rsi)"); @@ -719,6 +784,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { SIMPLE("xorl"); break; case OP_BCOM: + MAYBE_EMIT_CONST(); emit("notl 0(%%rsi)"); break; case OP_LSH: @@ -731,6 +797,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { SHIFT("shrl"); break; case OP_NEGF: + MAYBE_EMIT_CONST(); #ifdef USE_X87 emit("flds 0(%%rsi)"); emit("fchs"); @@ -757,6 +824,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { XSIMPLE("mulss"); break; case OP_CVIF: + MAYBE_EMIT_CONST(); #ifdef USE_X87 emit("filds 0(%%rsi)"); emit("fstps 0(%%rsi)"); @@ -767,6 +835,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { #endif break; case OP_CVFI: + MAYBE_EMIT_CONST(); #ifdef USE_X87 emit("flds 0(%%rsi)"); emit("fnstcw 4(%%rsi)"); @@ -784,8 +853,17 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { NOTIMPL(op); break; } + + } + if(got_const) { + Com_Error(ERR_DROP, "leftover const\n"); + } + + emit("movq $%lu, %%rax", (unsigned long)eop); + emit("callq *%%rax"); + } // pass loop assembler_init(0); @@ -798,6 +876,15 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { #ifdef DEBUG_VM fflush(qdasmout); fclose(qdasmout); + +#if 0 + strcpy(fn_d,vm->name); + strcat(fn_d, ".bin"); + qdasmout = fopen(fn_d, "w"); + fwrite(vm->codeBase, compiledOfs, 1, qdasmout); + fflush(qdasmout); + fclose(qdasmout); +#endif #endif if(vm->compiled)