X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Fmupen64plus-core%2Fsrc%2Fr4300%2Fx86_64%2Fgspecial.c;fp=source%2Fmupen64plus-core%2Fsrc%2Fr4300%2Fx86_64%2Fgspecial.c;h=e1624644753fd9dddb87b249c5a23e8f1f4924f6;hb=451ab91e3827a6384981b3300e2a7000d2eaba58;hp=0000000000000000000000000000000000000000;hpb=a2ab25365b5b0dddbee476d695d8a31151407581;p=mupen64plus-pandora.git diff --git a/source/mupen64plus-core/src/r4300/x86_64/gspecial.c b/source/mupen64plus-core/src/r4300/x86_64/gspecial.c new file mode 100644 index 0000000..e162464 --- /dev/null +++ b/source/mupen64plus-core/src/r4300/x86_64/gspecial.c @@ -0,0 +1,1062 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - gspecial.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007 Richard Goedeken (Richard42) * + * Copyright (C) 2002 Hacktarux * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include + +#include "assemble.h" +#include "interpret.h" + +#include "r4300/recomph.h" +#include "r4300/recomp.h" +#include "r4300/r4300.h" +#include "r4300/ops.h" +#include "r4300/macros.h" +#include "r4300/exception.h" + +#if !defined(offsetof) +# define offsetof(TYPE,MEMBER) ((unsigned int) &((TYPE*)0)->MEMBER) +#endif + +void gensll(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[55]); +#endif +#ifdef INTERPRET_SLL + gencallinterp((unsigned long long)cached_interpreter_table.SLL, 0); +#else + int rt = allocate_register_32((unsigned int *)dst->f.r.rt); + int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd, rt); + shl_reg32_imm8(rd, dst->f.r.sa); +#endif +} + +void gensrl(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[56]); +#endif +#ifdef INTERPRET_SRL + gencallinterp((unsigned long long)cached_interpreter_table.SRL, 0); +#else + int rt = allocate_register_32((unsigned int *)dst->f.r.rt); + int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd, rt); + shr_reg32_imm8(rd, dst->f.r.sa); +#endif +} + +void gensra(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[57]); +#endif +#ifdef INTERPRET_SRA + gencallinterp((unsigned long long)cached_interpreter_table.SRA, 0); +#else + int rt = allocate_register_32((unsigned int *)dst->f.r.rt); + int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + mov_reg32_reg32(rd, rt); + sar_reg32_imm8(rd, dst->f.r.sa); +#endif +} + +void gensllv(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[58]); +#endif +#ifdef INTERPRET_SLLV + gencallinterp((unsigned long long)cached_interpreter_table.SLLV, 0); +#else + int rt, rd; + allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); + + rt = allocate_register_32((unsigned int *)dst->f.r.rt); + rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(rd, rt); + shl_reg32_cl(rd); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rt); + shl_reg32_cl(temp); + mov_reg32_reg32(rd, temp); + } +#endif +} + +void gensrlv(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[59]); +#endif +#ifdef INTERPRET_SRLV + gencallinterp((unsigned long long)cached_interpreter_table.SRLV, 0); +#else + int rt, rd; + allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); + + rt = allocate_register_32((unsigned int *)dst->f.r.rt); + rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(rd, rt); + shr_reg32_cl(rd); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rt); + shr_reg32_cl(temp); + mov_reg32_reg32(rd, temp); + } +#endif +} + +void gensrav(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[60]); +#endif +#ifdef INTERPRET_SRAV + gencallinterp((unsigned long long)cached_interpreter_table.SRAV, 0); +#else + int rt, rd; + allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); + + rt = allocate_register_32((unsigned int *)dst->f.r.rt); + rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + if (rd != ECX) + { + mov_reg32_reg32(rd, rt); + sar_reg32_cl(rd); + } + else + { + int temp = lru_register(); + free_register(temp); + mov_reg32_reg32(temp, rt); + sar_reg32_cl(temp); + mov_reg32_reg32(rd, temp); + } +#endif +} + +void genjr(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[61]); +#endif +#ifdef INTERPRET_JR + gencallinterp((unsigned long long)cached_interpreter_table.JR, 1); +#else + static unsigned int precomp_instr_size = sizeof(precomp_instr); + unsigned int diff = (unsigned int) offsetof(precomp_instr, local_addr); + unsigned int diff_need = (unsigned int) offsetof(precomp_instr, reg_cache_infos.need_map); + unsigned int diff_wrap = (unsigned int) offsetof(precomp_instr, reg_cache_infos.jump_wrapper); + + if (((dst->addr & 0xFFF) == 0xFFC && + (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) + { + gencallinterp((unsigned long long)cached_interpreter_table.JR, 1); + return; + } + + free_registers_move_start(); + + mov_xreg32_m32rel(EAX, (unsigned int *)dst->f.i.rs); + mov_m32rel_xreg32((unsigned int *)&local_rs, EAX); + + gendelayslot(); + + mov_xreg32_m32rel(EAX, (unsigned int *)&local_rs); + mov_m32rel_xreg32((unsigned int *)&last_addr, EAX); + + gencheck_interupt_reg(); + + mov_xreg32_m32rel(EAX, (unsigned int *)&local_rs); + mov_reg32_reg32(EBX, EAX); + and_eax_imm32(0xFFFFF000); + cmp_eax_imm32(dst_block->start & 0xFFFFF000); + je_near_rj(0); + + jump_start_rel32(); + + mov_m32rel_xreg32(&jump_to_address, EBX); + mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); + mov_m64rel_xreg64((unsigned long long *)(&PC), RAX); + mov_reg64_imm64(RAX, (unsigned long long) jump_to_func); + call_reg64(RAX); /* will never return from call */ + + jump_end_rel32(); + + mov_reg64_imm64(RSI, (unsigned long long) dst_block->block); + mov_reg32_reg32(EAX, EBX); + sub_eax_imm32(dst_block->start); + shr_reg32_imm8(EAX, 2); + mul_m32rel((unsigned int *)(&precomp_instr_size)); + + mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff_need); + cmp_reg32_imm32(EBX, 1); + jne_rj(11); + + add_reg32_imm32(EAX, diff_wrap); // 6 + add_reg64_reg64(RAX, RSI); // 3 + jmp_reg64(RAX); // 2 + + mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff); + mov_rax_memoffs64((unsigned long long *) &dst_block->code); + add_reg64_reg64(RAX, RBX); + jmp_reg64(RAX); +#endif +} + +void genjalr(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[62]); +#endif +#ifdef INTERPRET_JALR + gencallinterp((unsigned long long)cached_interpreter_table.JALR, 0); +#else + static unsigned int precomp_instr_size = sizeof(precomp_instr); + unsigned int diff = (unsigned int) offsetof(precomp_instr, local_addr); + unsigned int diff_need = (unsigned int) offsetof(precomp_instr, reg_cache_infos.need_map); + unsigned int diff_wrap = (unsigned int) offsetof(precomp_instr, reg_cache_infos.jump_wrapper); + + if (((dst->addr & 0xFFF) == 0xFFC && + (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) + { + gencallinterp((unsigned long long)cached_interpreter_table.JALR, 1); + return; + } + + free_registers_move_start(); + + mov_xreg32_m32rel(EAX, (unsigned int *)dst->f.r.rs); + mov_m32rel_xreg32((unsigned int *)&local_rs, EAX); + + gendelayslot(); + + mov_m32rel_imm32((unsigned int *)(dst-1)->f.r.rd, dst->addr+4); + if ((dst->addr+4) & 0x80000000) + mov_m32rel_imm32(((unsigned int *)(dst-1)->f.r.rd)+1, 0xFFFFFFFF); + else + mov_m32rel_imm32(((unsigned int *)(dst-1)->f.r.rd)+1, 0); + + mov_xreg32_m32rel(EAX, (unsigned int *)&local_rs); + mov_m32rel_xreg32((unsigned int *)&last_addr, EAX); + + gencheck_interupt_reg(); + + mov_xreg32_m32rel(EAX, (unsigned int *)&local_rs); + mov_reg32_reg32(EBX, EAX); + and_eax_imm32(0xFFFFF000); + cmp_eax_imm32(dst_block->start & 0xFFFFF000); + je_near_rj(0); + + jump_start_rel32(); + + mov_m32rel_xreg32(&jump_to_address, EBX); + mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); + mov_m64rel_xreg64((unsigned long long *)(&PC), RAX); + mov_reg64_imm64(RAX, (unsigned long long) jump_to_func); + call_reg64(RAX); /* will never return from call */ + + jump_end_rel32(); + + mov_reg64_imm64(RSI, (unsigned long long) dst_block->block); + mov_reg32_reg32(EAX, EBX); + sub_eax_imm32(dst_block->start); + shr_reg32_imm8(EAX, 2); + mul_m32rel((unsigned int *)(&precomp_instr_size)); + + mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff_need); + cmp_reg32_imm32(EBX, 1); + jne_rj(11); + + add_reg32_imm32(EAX, diff_wrap); // 6 + add_reg64_reg64(RAX, RSI); // 3 + jmp_reg64(RAX); // 2 + + mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff); + mov_rax_memoffs64((unsigned long long *) &dst_block->code); + add_reg64_reg64(RAX, RBX); + jmp_reg64(RAX); +#endif +} + +void gensyscall(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[63]); +#endif +#ifdef INTERPRET_SYSCALL + gencallinterp((unsigned long long)cached_interpreter_table.SYSCALL, 0); +#else + free_registers_move_start(); + + mov_m32rel_imm32(&Cause, 8 << 2); + gencallinterp((unsigned long long)exception_general, 0); +#endif +} + +void gensync(void) +{ +} + +void genmfhi(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[64]); +#endif +#ifdef INTERPRET_MFHI + gencallinterp((unsigned long long)cached_interpreter_table.MFHI, 0); +#else + int rd = allocate_register_64_w((unsigned long long *) dst->f.r.rd); + int _hi = allocate_register_64((unsigned long long *) &hi); + + mov_reg64_reg64(rd, _hi); +#endif +} + +void genmthi(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[65]); +#endif +#ifdef INTERPRET_MTHI + gencallinterp((unsigned long long)cached_interpreter_table.MTHI, 0); +#else + int _hi = allocate_register_64_w((unsigned long long *) &hi); + int rs = allocate_register_64((unsigned long long *) dst->f.r.rs); + + mov_reg64_reg64(_hi, rs); +#endif +} + +void genmflo(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[66]); +#endif +#ifdef INTERPRET_MFLO + gencallinterp((unsigned long long)cached_interpreter_table.MFLO, 0); +#else + int rd = allocate_register_64_w((unsigned long long *) dst->f.r.rd); + int _lo = allocate_register_64((unsigned long long *) &lo); + + mov_reg64_reg64(rd, _lo); +#endif +} + +void genmtlo(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[67]); +#endif +#ifdef INTERPRET_MTLO + gencallinterp((unsigned long long)cached_interpreter_table.MTLO, 0); +#else + int _lo = allocate_register_64_w((unsigned long long *)&lo); + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + + mov_reg64_reg64(_lo, rs); +#endif +} + +void gendsllv(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[68]); +#endif +#ifdef INTERPRET_DSLLV + gencallinterp((unsigned long long)cached_interpreter_table.DSLLV, 0); +#else + int rt, rd; + allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); + + rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rd != ECX) + { + mov_reg64_reg64(rd, rt); + shl_reg64_cl(rd); + } + else + { + int temp; + temp = lru_register(); + free_register(temp); + + mov_reg64_reg64(temp, rt); + shl_reg64_cl(temp); + mov_reg64_reg64(rd, temp); + } +#endif +} + +void gendsrlv(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[69]); +#endif +#ifdef INTERPRET_DSRLV + gencallinterp((unsigned long long)cached_interpreter_table.DSRLV, 0); +#else + int rt, rd; + allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); + + rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rd != ECX) + { + mov_reg64_reg64(rd, rt); + shr_reg64_cl(rd); + } + else + { + int temp; + temp = lru_register(); + free_register(temp); + + mov_reg64_reg64(temp, rt); + shr_reg64_cl(temp); + mov_reg64_reg64(rd, temp); + } +#endif +} + +void gendsrav(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[70]); +#endif +#ifdef INTERPRET_DSRAV + gencallinterp((unsigned long long)cached_interpreter_table.DSRAV, 0); +#else + int rt, rd; + allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); + + rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rd != ECX) + { + mov_reg64_reg64(rd, rt); + sar_reg64_cl(rd); + } + else + { + int temp; + temp = lru_register(); + free_register(temp); + + mov_reg64_reg64(temp, rt); + sar_reg64_cl(temp); + mov_reg64_reg64(rd, temp); + } +#endif +} + +void genmult(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[71]); +#endif +#ifdef INTERPRET_MULT + gencallinterp((unsigned long long)cached_interpreter_table.MULT, 0); +#else + int rs, rt; + allocate_register_32_manually_w(EAX, (unsigned int *)&lo); /* these must be done first so they are not assigned by allocate_register() */ + allocate_register_32_manually_w(EDX, (unsigned int *)&hi); + rs = allocate_register_32((unsigned int*)dst->f.r.rs); + rt = allocate_register_32((unsigned int*)dst->f.r.rt); + mov_reg32_reg32(EAX, rs); + imul_reg32(rt); +#endif +} + +void genmultu(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[72]); +#endif +#ifdef INTERPRET_MULTU + gencallinterp((unsigned long long)cached_interpreter_table.MULTU, 0); +#else + int rs, rt; + allocate_register_32_manually_w(EAX, (unsigned int *)&lo); + allocate_register_32_manually_w(EDX, (unsigned int *)&hi); + rs = allocate_register_32((unsigned int*)dst->f.r.rs); + rt = allocate_register_32((unsigned int*)dst->f.r.rt); + mov_reg32_reg32(EAX, rs); + mul_reg32(rt); +#endif +} + +void gendiv(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[73]); +#endif +#ifdef INTERPRET_DIV + gencallinterp((unsigned long long)cached_interpreter_table.DIV, 0); +#else + int rs, rt; + allocate_register_32_manually_w(EAX, (unsigned int *)&lo); + allocate_register_32_manually_w(EDX, (unsigned int *)&hi); + rs = allocate_register_32((unsigned int*)dst->f.r.rs); + rt = allocate_register_32((unsigned int*)dst->f.r.rt); + cmp_reg32_imm32(rt, 0); + je_rj((rs == EAX ? 0 : 2) + 1 + 2); + mov_reg32_reg32(EAX, rs); // 0 or 2 + cdq(); // 1 + idiv_reg32(rt); // 2 +#endif +} + +void gendivu(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[74]); +#endif +#ifdef INTERPRET_DIVU + gencallinterp((unsigned long long)cached_interpreter_table.DIVU, 0); +#else + int rs, rt; + allocate_register_32_manually_w(EAX, (unsigned int *)&lo); + allocate_register_32_manually_w(EDX, (unsigned int *)&hi); + rs = allocate_register_32((unsigned int*)dst->f.r.rs); + rt = allocate_register_32((unsigned int*)dst->f.r.rt); + cmp_reg32_imm32(rt, 0); + je_rj((rs == EAX ? 0 : 2) + 2 + 2); + mov_reg32_reg32(EAX, rs); // 0 or 2 + xor_reg32_reg32(EDX, EDX); // 2 + div_reg32(rt); // 2 +#endif +} + +void gendmult(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[75]); +#endif + gencallinterp((unsigned long long)cached_interpreter_table.DMULT, 0); +} + +void gendmultu(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[76]); +#endif +#ifdef INTERPRET_DMULTU + gencallinterp((unsigned long long)cached_interpreter_table.DMULTU, 0); +#else + free_registers_move_start(); + + mov_xreg64_m64rel(RAX, (unsigned long long *) dst->f.r.rs); + mov_xreg64_m64rel(RDX, (unsigned long long *) dst->f.r.rt); + mul_reg64(RDX); + mov_m64rel_xreg64((unsigned long long *) &lo, RAX); + mov_m64rel_xreg64((unsigned long long *) &hi, RDX); +#endif +} + +void genddiv(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[77]); +#endif + gencallinterp((unsigned long long)cached_interpreter_table.DDIV, 0); +} + +void genddivu(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[78]); +#endif + gencallinterp((unsigned long long)cached_interpreter_table.DDIVU, 0); +} + +void genadd(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[79]); +#endif +#ifdef INTERPRET_ADD + gencallinterp((unsigned long long)cached_interpreter_table.ADD, 0); +#else + int rs = allocate_register_32((unsigned int *)dst->f.r.rs); + int rt = allocate_register_32((unsigned int *)dst->f.r.rt); + int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + if (rs == rd) + add_reg32_reg32(rd, rt); + else if (rt == rd) + add_reg32_reg32(rd, rs); + else + { + mov_reg32_reg32(rd, rs); + add_reg32_reg32(rd, rt); + } +#endif +} + +void genaddu(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[80]); +#endif +#ifdef INTERPRET_ADDU + gencallinterp((unsigned long long)cached_interpreter_table.ADDU, 0); +#else + int rs = allocate_register_32((unsigned int *)dst->f.r.rs); + int rt = allocate_register_32((unsigned int *)dst->f.r.rt); + int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + if (rs == rd) + add_reg32_reg32(rd, rt); + else if (rt == rd) + add_reg32_reg32(rd, rs); + else + { + mov_reg32_reg32(rd, rs); + add_reg32_reg32(rd, rt); + } +#endif +} + +void gensub(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[81]); +#endif +#ifdef INTERPRET_SUB + gencallinterp((unsigned long long)cached_interpreter_table.SUB, 0); +#else + int rs = allocate_register_32((unsigned int *)dst->f.r.rs); + int rt = allocate_register_32((unsigned int *)dst->f.r.rt); + int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + if (rs == rd) + sub_reg32_reg32(rd, rt); + else if (rt == rd) + { + neg_reg32(rd); + add_reg32_reg32(rd, rs); + } + else + { + mov_reg32_reg32(rd, rs); + sub_reg32_reg32(rd, rt); + } +#endif +} + +void gensubu(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[82]); +#endif +#ifdef INTERPRET_SUBU + gencallinterp((unsigned long long)cached_interpreter_table.SUBU, 0); +#else + int rs = allocate_register_32((unsigned int *)dst->f.r.rs); + int rt = allocate_register_32((unsigned int *)dst->f.r.rt); + int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); + + if (rs == rd) + sub_reg32_reg32(rd, rt); + else if (rt == rd) + { + neg_reg32(rd); + add_reg32_reg32(rd, rs); + } + else + { + mov_reg32_reg32(rd, rs); + sub_reg32_reg32(rd, rt); + } +#endif +} + +void genand(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[83]); +#endif +#ifdef INTERPRET_AND + gencallinterp((unsigned long long)cached_interpreter_table.AND, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rs == rd) + and_reg64_reg64(rd, rt); + else if (rt == rd) + and_reg64_reg64(rd, rs); + else + { + mov_reg64_reg64(rd, rs); + and_reg64_reg64(rd, rt); + } +#endif +} + +void genor(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[84]); +#endif +#ifdef INTERPRET_OR + gencallinterp((unsigned long long)cached_interpreter_table.OR, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rs == rd) + or_reg64_reg64(rd, rt); + else if (rt == rd) + or_reg64_reg64(rd, rs); + else + { + mov_reg64_reg64(rd, rs); + or_reg64_reg64(rd, rt); + } +#endif +} + +void genxor(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[85]); +#endif +#ifdef INTERPRET_XOR + gencallinterp((unsigned long long)cached_interpreter_table.XOR, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rs == rd) + xor_reg64_reg64(rd, rt); + else if (rt == rd) + xor_reg64_reg64(rd, rs); + else + { + mov_reg64_reg64(rd, rs); + xor_reg64_reg64(rd, rt); + } +#endif +} + +void gennor(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[86]); +#endif +#ifdef INTERPRET_NOR + gencallinterp((unsigned long long)cached_interpreter_table.NOR, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rs == rd) + { + or_reg64_reg64(rd, rt); + not_reg64(rd); + } + else if (rt == rd) + { + or_reg64_reg64(rd, rs); + not_reg64(rd); + } + else + { + mov_reg64_reg64(rd, rs); + or_reg64_reg64(rd, rt); + not_reg64(rd); + } +#endif +} + +void genslt(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[87]); +#endif +#ifdef INTERPRET_SLT + gencallinterp((unsigned long long)cached_interpreter_table.SLT, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + cmp_reg64_reg64(rs, rt); + setl_reg8(rd); + and_reg64_imm8(rd, 1); +#endif +} + +void gensltu(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[88]); +#endif +#ifdef INTERPRET_SLTU + gencallinterp((unsigned long long)cached_interpreter_table.SLTU, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + cmp_reg64_reg64(rs, rt); + setb_reg8(rd); + and_reg64_imm8(rd, 1); +#endif +} + +void gendadd(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[89]); +#endif +#ifdef INTERPRET_DADD + gencallinterp((unsigned long long)cached_interpreter_table.DADD, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rs == rd) + add_reg64_reg64(rd, rt); + else if (rt == rd) + add_reg64_reg64(rd, rs); + else + { + mov_reg64_reg64(rd, rs); + add_reg64_reg64(rd, rt); + } +#endif +} + +void gendaddu(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[90]); +#endif +#ifdef INTERPRET_DADDU + gencallinterp((unsigned long long)cached_interpreter_table.DADDU, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rs == rd) + add_reg64_reg64(rd, rt); + else if (rt == rd) + add_reg64_reg64(rd, rs); + else + { + mov_reg64_reg64(rd, rs); + add_reg64_reg64(rd, rt); + } +#endif +} + +void gendsub(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[91]); +#endif +#ifdef INTERPRET_DSUB + gencallinterp((unsigned long long)cached_interpreter_table.DSUB, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rs == rd) + sub_reg64_reg64(rd, rt); + else if (rt == rd) + { + neg_reg64(rd); + add_reg64_reg64(rd, rs); + } + else + { + mov_reg64_reg64(rd, rs); + sub_reg64_reg64(rd, rt); + } +#endif +} + +void gendsubu(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[92]); +#endif +#ifdef INTERPRET_DSUBU + gencallinterp((unsigned long long)cached_interpreter_table.DSUBU, 0); +#else + int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + if (rs == rd) + sub_reg64_reg64(rd, rt); + else if (rt == rd) + { + neg_reg64(rd); + add_reg64_reg64(rd, rs); + } + else + { + mov_reg64_reg64(rd, rs); + sub_reg64_reg64(rd, rt); + } +#endif +} + +void genteq(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[96]); +#endif + gencallinterp((unsigned long long)cached_interpreter_table.TEQ, 0); +} + +void gendsll(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[93]); +#endif +#ifdef INTERPRET_DSLL + gencallinterp((unsigned long long)cached_interpreter_table.DSLL, 0); +#else + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + mov_reg64_reg64(rd, rt); + shl_reg64_imm8(rd, dst->f.r.sa); +#endif +} + +void gendsrl(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[94]); +#endif +#ifdef INTERPRET_DSRL + gencallinterp((unsigned long long)cached_interpreter_table.DSRL, 0); +#else + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + mov_reg64_reg64(rd, rt); + shr_reg64_imm8(rd, dst->f.r.sa); +#endif +} + +void gendsra(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[95]); +#endif +#ifdef INTERPRET_DSRA + gencallinterp((unsigned long long)cached_interpreter_table.DSRA, 0); +#else + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + mov_reg64_reg64(rd, rt); + sar_reg64_imm8(rd, dst->f.r.sa); +#endif +} + +void gendsll32(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[97]); +#endif +#ifdef INTERPRET_DSLL32 + gencallinterp((unsigned long long)cached_interpreter_table.DSLL32, 0); +#else + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + mov_reg64_reg64(rd, rt); + shl_reg64_imm8(rd, dst->f.r.sa + 32); +#endif +} + +void gendsrl32(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[98]); +#endif +#ifdef INTERPRET_DSRL32 + gencallinterp((unsigned long long)cached_interpreter_table.DSRL32, 0); +#else + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + mov_reg64_reg64(rd, rt); + shr_reg64_imm8(rd, dst->f.r.sa + 32); +#endif +} + +void gendsra32(void) +{ +#if defined(COUNT_INSTR) + inc_m32rel(&instr_count[99]); +#endif +#ifdef INTERPRET_DSRA32 + gencallinterp((unsigned long long)cached_interpreter_table.DSRA32, 0); +#else + int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); + int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); + + mov_reg64_reg64(rd, rt); + sar_reg64_imm8(rd, dst->f.r.sa + 32); +#endif +} +