diff --git a/SheepShaver/src/Unix/Makefile.in b/SheepShaver/src/Unix/Makefile.in index b361b06b..b516405a 100644 --- a/SheepShaver/src/Unix/Makefile.in +++ b/SheepShaver/src/Unix/Makefile.in @@ -228,9 +228,9 @@ ppc-execute-impl.cpp: $(kpxsrcdir)/cpu/ppc/ppc-decode.cpp $(GENEXECPL) $(DYNGEND $(CPP) $(CPPFLAGS) -DGENEXEC $< | $(PERL) $(GENEXECPL) > $@ # PowerPC CPU tester -TESTSRCS_ = mathlib/ieeefp.cpp mathlib/mathlib.cpp cpu/ppc/ppc-cpu.cpp cpu/ppc/ppc-decode.cpp cpu/ppc/ppc-execute.cpp cpu/ppc/ppc-translate.cpp test/test-powerpc.cpp $(MONSRCS) vm_alloc.cpp +TESTSRCS_ = mathlib/ieeefp.cpp mathlib/mathlib.cpp cpu/ppc/ppc-cpu.cpp cpu/ppc/ppc-decode.cpp cpu/ppc/ppc-execute.cpp cpu/ppc/ppc-translate.cpp test/test-powerpc.cpp $(MONSRCS) vm_alloc.cpp utils/utils-cpuinfo.cpp ifeq ($(USE_DYNGEN),yes) -TESTSRCS_ += cpu/jit/jit-cache.cpp cpu/jit/basic-dyngen.cpp cpu/ppc/ppc-dyngen.cpp +TESTSRCS_ += cpu/jit/jit-cache.cpp cpu/jit/basic-dyngen.cpp cpu/ppc/ppc-dyngen.cpp cpu/ppc/ppc-jit.cpp endif TESTSRCS = $(TESTSRCS_:%.cpp=$(kpxsrcdir)/%.cpp) diff --git a/SheepShaver/src/Unix/configure.ac b/SheepShaver/src/Unix/configure.ac index 4b70f624..971f8643 100644 --- a/SheepShaver/src/Unix/configure.ac +++ b/SheepShaver/src/Unix/configure.ac @@ -1347,7 +1347,8 @@ if [[ "x$EMULATED_PPC" = "xyes" ]]; then ../kpx_cpu/src/cpu/ppc/ppc-cpu.cpp \ ../kpx_cpu/src/cpu/ppc/ppc-decode.cpp \ ../kpx_cpu/src/cpu/ppc/ppc-execute.cpp \ - ../kpx_cpu/src/cpu/ppc/ppc-translate.cpp" + ../kpx_cpu/src/cpu/ppc/ppc-translate.cpp \ + ../kpx_cpu/src/utils/utils-cpuinfo.cpp" CPPFLAGS="$CPPFLAGS -I../kpx_cpu/include -I../kpx_cpu/src" dnl Enable JIT compiler, if possible @@ -1440,7 +1441,8 @@ if [[ "x$EMULATED_PPC" = "xyes" ]]; then CPUSRCS="\ ../kpx_cpu/src/cpu/jit/jit-cache.cpp \ ../kpx_cpu/src/cpu/jit/basic-dyngen.cpp \ - ../kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp $CPUSRCS" + ../kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp \ + ../kpx_cpu/src/cpu/ppc/ppc-jit.cpp $CPUSRCS" fi fi CPUSRCS="$CPUSRCS ../kpx_cpu/sheepshaver_glue.cpp" diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp index 9caf7a68..c7958ff1 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-cpu.hpp @@ -29,7 +29,7 @@ #include "cpu/ppc/ppc-bitfields.hpp" #include "cpu/ppc/ppc-blockinfo.hpp" #include "cpu/ppc/ppc-registers.hpp" -#include "cpu/ppc/ppc-dyngen.hpp" +#include "cpu/ppc/ppc-jit.hpp" #include "cpu/ppc/ppc-instructions.hpp" #include @@ -374,7 +374,7 @@ private: // Dynamic translation engine friend class powerpc_dyngen_helper; friend class powerpc_dyngen; - powerpc_dyngen codegen; + powerpc_jit codegen; block_info *compile_block(uint32 entry); #if DYNGEN_DIRECT_BLOCK_CHAINING void *compile_chain_block(block_info *sbi); diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp index 3ebbd261..87defdad 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.cpp @@ -1,5 +1,5 @@ /* - * ppc-dyngen.cpp - PowerPC dynamic translation + * ppc-dyngen.cpp - PowerPC dynamic translation (low-level) * * Kheperix (C) 2003-2005 Gwenole Beauchesne * @@ -19,6 +19,7 @@ */ #include "sysdeps.h" +#include "utils/utils-cpuinfo.hpp" #include "cpu/ppc/ppc-dyngen.hpp" #include "cpu/ppc/ppc-bitfields.hpp" #include "cpu/ppc/ppc-instructions.hpp" @@ -30,87 +31,24 @@ #define DEFINE_GEN(NAME,RET,ARGS) RET powerpc_dyngen::NAME ARGS #include "ppc-dyngen-ops.hpp" - -/** - * Determine x86 CPU features - **/ - -/* XXX: move that in CPU dependent bits */ -#if defined(__i386__) || defined(__x86_64__) -static uint32 cpu_features = 0; - -enum { - HWCAP_I386_CMOV = 1 << 15, - HWCAP_I386_MMX = 1 << 23, - HWCAP_I386_SSE = 1 << 25, - HWCAP_I386_SSE2 = 1 << 26, - HWCAP_I386_EDX_FLAGS = (HWCAP_I386_CMOV|HWCAP_I386_MMX|HWCAP_I386_SSE|HWCAP_I386_SSE2), - HWCAP_I386_SSE3 = 1 << 0, - HWCAP_I386_SSE4 = 1 << 9, - HWCAP_I386_ECX_FLAGS = (HWCAP_I386_SSE3|HWCAP_I386_SSE4), -}; - -static uint32 x86_cpuid(void) -{ - int fl1, fl2; - -#ifndef __x86_64__ - /* See if we can use cpuid. On AMD64 we always can. */ - __asm__ ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;" - "pushl %0; popfl; pushfl; popl %0; popfl" - : "=&r" (fl1), "=&r" (fl2) - : "i" (0x00200000)); - if (((fl1 ^ fl2) & 0x00200000) == 0) - return (0); -#endif - - /* Host supports cpuid. See if cpuid gives capabilities, try - CPUID(0). Preserve %ebx and %ecx; cpuid insn clobbers these, we - don't need their CPUID values here, and %ebx may be the PIC - register. */ -#ifdef __x86_64__ - __asm__ ("pushq %%rcx; pushq %%rbx; cpuid; popq %%rbx; popq %%rcx" - : "=a" (fl1) : "0" (0) : "rdx", "cc"); -#else - __asm__ ("push %%ecx ; push %%ebx ; cpuid ; pop %%ebx ; pop %%ecx" - : "=a" (fl1) : "0" (0) : "edx", "cc"); -#endif - if (fl1 == 0) - return (0); - - /* Invoke CPUID(1), return %edx; caller can examine bits to - determine what's supported. */ -#ifdef __x86_64__ - __asm__ ("push %%rbx ; cpuid ; pop %%rbx" : "=c" (fl1), "=d" (fl2) : "a" (1) : "cc"); -#else - __asm__ ("push %%ebx ; cpuid ; pop %%ebx" : "=c" (fl1), "=d" (fl2) : "a" (1) : "cc"); -#endif - - return (fl1 & HWCAP_I386_ECX_FLAGS) | (fl2 & HWCAP_I386_EDX_FLAGS); -} -#endif - powerpc_dyngen::powerpc_dyngen(dyngen_cpu_base cpu, int cache_size) : basic_dyngen(cpu, cache_size) { -#if defined(__i386__) || defined(__x86_64__) - cpu_features = x86_cpuid(); #ifdef SHEEPSHAVER - if (cpu_features & (HWCAP_I386_MMX | HWCAP_I386_SSE | HWCAP_I386_SSE2)) { - printf("Detected CPU features:"); - if (cpu_features & HWCAP_I386_MMX) - printf(" MMX"); - if (cpu_features & HWCAP_I386_SSE) - printf(" SSE"); - if (cpu_features & HWCAP_I386_SSE2) - printf(" SSE2"); - if (cpu_features & HWCAP_I386_SSE3) - printf(" SSE3"); - if (cpu_features & HWCAP_I386_SSE4) - printf(" SSE4"); - printf("\n"); - } -#endif + printf("Detected CPU features:"); + if (cpuinfo_check_mmx()) + printf(" MMX"); + if (cpuinfo_check_sse()) + printf(" SSE"); + if (cpuinfo_check_sse2()) + printf(" SSE2"); + if (cpuinfo_check_sse3()) + printf(" SSE3"); + if (cpuinfo_check_sse4()) + printf(" SSE4"); + if (cpuinfo_check_altivec()) + printf(" VMX"); + printf("\n"); #endif } @@ -370,123 +308,10 @@ void powerpc_dyngen::gen_store_vect_VS_T0(int vS) gen_op_store_vect_VD_T0(); } -/** - * Code generators for AltiVec instructions - **/ - -powerpc_dyngen::gen_handler_t -powerpc_dyngen::vector_codegen(int insn) +void powerpc_dyngen::gen_sse2_vsldoi_VD_V0_V1(int SH) { - gen_handler_t gen_op = 0; - switch (insn) { -#define GEN_OP(NAME) nv_mem_fun(&powerpc_dyngen::gen_op_##NAME) - case PPC_I(VADDFP): gen_op = GEN_OP(vaddfp_VD_V0_V1); break; - case PPC_I(VSUBFP): gen_op = GEN_OP(vsubfp_VD_V0_V1); break; - case PPC_I(VMADDFP): gen_op = GEN_OP(vmaddfp_VD_V0_V1_V2); break; - case PPC_I(VNMSUBFP): gen_op = GEN_OP(vnmsubfp_VD_V0_V1_V2); break; - case PPC_I(VAND): gen_op = GEN_OP(vand_VD_V0_V1); break; - case PPC_I(VANDC): gen_op = GEN_OP(vandc_VD_V0_V1); break; - case PPC_I(VNOR): gen_op = GEN_OP(vnor_VD_V0_V1); break; - case PPC_I(VOR): gen_op = GEN_OP(vor_VD_V0_V1); break; - case PPC_I(VXOR): gen_op = GEN_OP(vxor_VD_V0_V1); break; -#undef GEN_OP - } - return gen_op; -} - #if defined(__i386__) || defined(__x86_64__) -powerpc_dyngen::gen_handler_t -powerpc_dyngen::vector_codegen_mmx(int insn) -{ - if (!(cpu_features & HWCAP_I386_MMX)) - return 0; - - /* XXX: auto-generate the table with individual handlers */ - gen_handler_t gen_op = 0; - switch (insn) { -#define GEN_OP(NAME) nv_mem_fun(&powerpc_dyngen::gen_op_mmx_##NAME) - case PPC_I(VADDUBM): gen_op = GEN_OP(vaddubm); break; - case PPC_I(VADDUHM): gen_op = GEN_OP(vadduhm); break; - case PPC_I(VADDUWM): gen_op = GEN_OP(vadduwm); break; - case PPC_I(VAND): gen_op = GEN_OP(vand); break; - case PPC_I(VANDC): gen_op = GEN_OP(vandc); break; - case PPC_I(VCMPEQUB): gen_op = GEN_OP(vcmpequb); break; - case PPC_I(VCMPEQUH): gen_op = GEN_OP(vcmpequh); break; - case PPC_I(VCMPEQUW): gen_op = GEN_OP(vcmpequw); break; - case PPC_I(VCMPGTSB): gen_op = GEN_OP(vcmpgtsb); break; - case PPC_I(VCMPGTSH): gen_op = GEN_OP(vcmpgtsh); break; - case PPC_I(VCMPGTSW): gen_op = GEN_OP(vcmpgtsw); break; - case PPC_I(VOR): gen_op = GEN_OP(vor); break; - case PPC_I(VSUBUBM): gen_op = GEN_OP(vsububm); break; - case PPC_I(VSUBUHM): gen_op = GEN_OP(vsubuhm); break; - case PPC_I(VSUBUWM): gen_op = GEN_OP(vsubuwm); break; - case PPC_I(VXOR): gen_op = GEN_OP(vxor); break; -#undef GEN_OP - } - - if (gen_op.ptr()) - return gen_op; - - // new MMX instructions brought in SSE capable CPUs - // XXX: also available as AMD MMX extensions - if (!(cpu_features & HWCAP_I386_SSE)) - return 0; - - switch (insn) { -#define GEN_OP(NAME) nv_mem_fun(&powerpc_dyngen::gen_op_mmx_##NAME) - case PPC_I(VMAXSH): gen_op = GEN_OP(vmaxsh); break; - case PPC_I(VMAXUB): gen_op = GEN_OP(vmaxub); break; - case PPC_I(VMINSH): gen_op = GEN_OP(vminsh); break; - case PPC_I(VMINUB): gen_op = GEN_OP(vminub); break; -#undef GEN_OP - } - return gen_op; -} - -powerpc_dyngen::gen_handler_t -powerpc_dyngen::vector_codegen_sse(int insn) -{ - if (!(cpu_features & HWCAP_I386_SSE)) - return 0; - - /* XXX: auto-generate the table with individual handlers */ - gen_handler_t gen_op = 0; - switch (insn) { -#define GEN_OP(NAME) nv_mem_fun(&powerpc_dyngen::gen_op_sse_##NAME) - case PPC_I(VADDFP): gen_op = GEN_OP(vaddfp); break; - case PPC_I(VAND): gen_op = GEN_OP(vand); break; - case PPC_I(VANDC): gen_op = GEN_OP(vandc); break; - case PPC_I(VCMPEQFP): gen_op = GEN_OP(vcmpeqfp); break; - case PPC_I(VCMPGEFP): gen_op = GEN_OP(vcmpgefp); break; - case PPC_I(VCMPGTFP): gen_op = GEN_OP(vcmpgtfp); break; - case PPC_I(VMADDFP): gen_op = GEN_OP(vmaddfp); break; - case PPC_I(VMAXFP): gen_op = GEN_OP(vmaxfp); break; - case PPC_I(VMINFP): gen_op = GEN_OP(vminfp); break; - case PPC_I(VNMSUBFP): gen_op = GEN_OP(vnmsubfp); break; - case PPC_I(VOR): gen_op = GEN_OP(vor); break; - case PPC_I(VSUBFP): gen_op = GEN_OP(vsubfp); break; - case PPC_I(VXOR): gen_op = GEN_OP(vxor); break; - case PPC_I(VMINUB): gen_op = GEN_OP(vminub); break; - case PPC_I(VMAXUB): gen_op = GEN_OP(vmaxub); break; - case PPC_I(VMINSH): gen_op = GEN_OP(vminsh); break; - case PPC_I(VMAXSH): gen_op = GEN_OP(vmaxsh); break; -#undef GEN_OP - } - return gen_op; -} - -bool powerpc_dyngen::gen_vector_shift_octet(int vD, int vA, int vB, int SH) -{ - if (!(cpu_features & HWCAP_I386_SSE2)) - return false; - - gen_load_ad_VD_VR(vD); - gen_load_ad_V0_VR(vA); - if (SH == 0) - gen_op_sse_mov_VD_V0(); - else { - gen_load_ad_V1_VR(vB); - switch (SH) { + switch (SH) { #define GEN_OP(SH) case SH: gen_op_sse2_vsldoi_##SH(); break GEN_OP(1); GEN_OP(2); @@ -504,46 +329,7 @@ bool powerpc_dyngen::gen_vector_shift_octet(int vD, int vA, int vB, int SH) GEN_OP(14); GEN_OP(15); #undef GEN_OP - default: abort(); - } + default: abort(); } - return true; -} - -powerpc_dyngen::gen_handler_t -powerpc_dyngen::vector_codegen_sse2(int insn) -{ - if (!(cpu_features & HWCAP_I386_SSE2)) - return 0; - - /* XXX: auto-generate the table with individual handlers */ - gen_handler_t gen_op = 0; - switch (insn) { -#define GEN_OP(NAME) nv_mem_fun(&powerpc_dyngen::gen_op_sse2_##NAME) - case PPC_I(VADDUBM): gen_op = GEN_OP(vaddubm); break; - case PPC_I(VADDUHM): gen_op = GEN_OP(vadduhm); break; - case PPC_I(VADDUWM): gen_op = GEN_OP(vadduwm); break; - case PPC_I(VSUBUBM): gen_op = GEN_OP(vsububm); break; - case PPC_I(VSUBUHM): gen_op = GEN_OP(vsubuhm); break; - case PPC_I(VSUBUWM): gen_op = GEN_OP(vsubuwm); break; - case PPC_I(VAND): gen_op = GEN_OP(vand); break; - case PPC_I(VANDC): gen_op = GEN_OP(vandc); break; - case PPC_I(VOR): gen_op = GEN_OP(vor); break; - case PPC_I(VXOR): gen_op = GEN_OP(vxor); break; - case PPC_I(VCMPEQUB): gen_op = GEN_OP(vcmpequb); break; - case PPC_I(VCMPEQUH): gen_op = GEN_OP(vcmpequh); break; - case PPC_I(VCMPEQUW): gen_op = GEN_OP(vcmpequw); break; - case PPC_I(VCMPGTSB): gen_op = GEN_OP(vcmpgtsb); break; - case PPC_I(VCMPGTSH): gen_op = GEN_OP(vcmpgtsh); break; - case PPC_I(VCMPGTSW): gen_op = GEN_OP(vcmpgtsw); break; -#undef GEN_OP - } - return gen_op; -} - -void powerpc_dyngen::gen_mmx_clear(void) -{ - if (cpu_features & HWCAP_I386_MMX) - gen_op_emms(); -} #endif +} diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp index ace2dcf2..65d3c0f3 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-dyngen.hpp @@ -1,5 +1,5 @@ /* - * ppc-dyngen.hpp - PowerPC dynamic translation + * ppc-dyngen.hpp - PowerPC dynamic translation (low-level) * * Kheperix (C) 2003-2005 Gwenole Beauchesne * @@ -32,19 +32,18 @@ class powerpc_dyngen : public basic_dyngen { +#ifndef REG_T3 + uintptr reg_T3; +#endif + // Code generators for PowerPC synthetic instructions #ifndef NO_DEFINE_ALIAS # define DEFINE_GEN(NAME,RET,ARGS) RET NAME ARGS; # include "ppc-dyngen-ops.hpp" #endif -#ifndef REG_T3 - uintptr reg_T3; -#endif - public: - - // Make rc_cache accessible to codegen helper + friend class powerpc_jit; friend class powerpc_dyngen_helper; // Code generators @@ -235,16 +234,7 @@ public: DEFINE_ALIAS(record_cr6_VD,0); DEFINE_ALIAS(mfvscr_VD,0); DEFINE_ALIAS(mtvscr_V0,0); - - // Code generators for AltiVec instructions - gen_handler_t vector_codegen(int insn); -#if defined(__i386__) || defined(__x86_64__) - gen_handler_t vector_codegen_mmx(int insn); - gen_handler_t vector_codegen_sse(int insn); - gen_handler_t vector_codegen_sse2(int insn); - void gen_mmx_clear(void); - bool gen_vector_shift_octet(int vD, int vA, int vB, int SH); -#endif + void gen_sse2_vsldoi_VD_V0_V1(int SH); #undef DEFINE_ALIAS #undef DEFINE_ALIAS_0 diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.cpp new file mode 100644 index 00000000..d1cdb06b --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.cpp @@ -0,0 +1,234 @@ +/* + * ppc-jit.cpp - PowerPC dynamic translation (mid-level) + * + * Kheperix (C) 2003-2005 Gwenole Beauchesne + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" +#include "cpu/ppc/ppc-jit.hpp" +#include "cpu/ppc/ppc-instructions.hpp" +#include "utils/utils-cpuinfo.hpp" +#include "utils/utils-sentinel.hpp" + +// Mid-level code generator info +const powerpc_jit::jit_info_t *powerpc_jit::jit_info[PPC_I(MAX)]; + +// PowerPC JIT initializer +powerpc_jit::powerpc_jit(dyngen_cpu_base cpu, int cache_size) + : powerpc_dyngen(cpu, cache_size) +{ + static bool once = true; + + if (once) { + once = false; + + // default to no handler + static const jit_info_t jit_not_available = { + -1, + (gen_handler_t)&powerpc_jit::gen_not_available, + 0 + }; + for (int i = 0; i < PPC_I(MAX); i++) + jit_info[i] = &jit_not_available; + + // generic altivec handlers + static const jit_info_t gen_vector[] = { +#define DEFINE_OP(MNEMO, GEN_OP, DYNGEN_OP) \ + { PPC_I(MNEMO), (gen_handler_t)&powerpc_jit::gen_vector_generic_##GEN_OP, &powerpc_dyngen::gen_op_##DYNGEN_OP } + DEFINE_OP(VADDFP, 2, vaddfp_VD_V0_V1), + DEFINE_OP(VSUBFP, 2, vsubfp_VD_V0_V1), + DEFINE_OP(VMADDFP, 3, vmaddfp_VD_V0_V1_V2), + DEFINE_OP(VNMSUBFP, 3, vnmsubfp_VD_V0_V1_V2), + DEFINE_OP(VAND, 2, vand_VD_V0_V1), + DEFINE_OP(VANDC, 2, vandc_VD_V0_V1), + DEFINE_OP(VNOR, 2, vnor_VD_V0_V1), + DEFINE_OP(VOR, 2, vor_VD_V0_V1), + DEFINE_OP(VXOR, 2, vxor_VD_V0_V1) +#undef DEFINE_OP + }; + for (int i = 0; i < sizeof(gen_vector) / sizeof(gen_vector[0]); i++) + jit_info[gen_vector[i].mnemo] = &gen_vector[i]; + +#if defined(__i386__) || defined(__x86_64__) + // MMX optimized handlers + static const jit_info_t mmx_vector[] = { +#define DEFINE_OP(MNEMO, GEN_OP, DYNGEN_OP) \ + { PPC_I(MNEMO), (gen_handler_t)&powerpc_jit::gen_vector_mmx_##GEN_OP, &powerpc_dyngen::gen_op_mmx_##DYNGEN_OP } + DEFINE_OP(VADDUBM, 2, vaddubm), + DEFINE_OP(VADDUHM, 2, vadduhm), + DEFINE_OP(VADDUWM, 2, vadduwm), + DEFINE_OP(VAND, 2, vand), + DEFINE_OP(VANDC, 2, vandc), + DEFINE_OP(VCMPEQUB, 2, vcmpequb), + DEFINE_OP(VCMPEQUH, 2, vcmpequh), + DEFINE_OP(VCMPEQUW, 2, vcmpequw), + DEFINE_OP(VCMPGTSB, 2, vcmpgtsb), + DEFINE_OP(VCMPGTSH, 2, vcmpgtsh), + DEFINE_OP(VCMPGTSW, 2, vcmpgtsw), + DEFINE_OP(VOR, 2, vor), + DEFINE_OP(VSUBUBM, 2, vsububm), + DEFINE_OP(VSUBUHM, 2, vsubuhm), + DEFINE_OP(VSUBUWM, 2, vsubuwm), + DEFINE_OP(VXOR, 2, vxor) +#undef DEFINE_OP + }; + if (cpuinfo_check_mmx()) { + for (int i = 0; i < sizeof(mmx_vector) / sizeof(mmx_vector[0]); i++) + jit_info[mmx_vector[i].mnemo] = &mmx_vector[i]; + } + + // SSE optimized handlers + static const jit_info_t sse_vector[] = { + // new MMX instructions brought into SSE capable CPUs +#define DEFINE_OP(MNEMO, GEN_OP, DYNGEN_OP) \ + { PPC_I(MNEMO), (gen_handler_t)&powerpc_jit::gen_vector_mmx_##GEN_OP, &powerpc_dyngen::gen_op_mmx_##DYNGEN_OP } + DEFINE_OP(VMAXSH, 2, vmaxsh), + DEFINE_OP(VMAXUB, 2, vmaxub), + DEFINE_OP(VMINSH, 2, vminsh), + DEFINE_OP(VMINUB, 2, vminub), +#undef DEFINE_OP + // full SSE instructions +#define DEFINE_OP(MNEMO, GEN_OP, DYNGEN_OP) \ + { PPC_I(MNEMO), (gen_handler_t)&powerpc_jit::gen_vector_generic_##GEN_OP, &powerpc_dyngen::gen_op_sse_##DYNGEN_OP } + DEFINE_OP(VADDFP, 2, vaddfp), + DEFINE_OP(VAND, 2, vand), + DEFINE_OP(VANDC, 2, vandc), + DEFINE_OP(VCMPEQFP, 2, vcmpeqfp), + DEFINE_OP(VCMPGEFP, 2, vcmpgefp), + DEFINE_OP(VCMPGTFP, 2, vcmpgtfp), + DEFINE_OP(VMADDFP, 3, vmaddfp), + DEFINE_OP(VMAXFP, 2, vmaxfp), + DEFINE_OP(VMINFP, 2, vminfp), + DEFINE_OP(VNMSUBFP, 3, vnmsubfp), + DEFINE_OP(VOR, 2, vor), + DEFINE_OP(VSUBFP, 2, vsubfp), + DEFINE_OP(VXOR, 2, vxor), + DEFINE_OP(VMINUB, 2, vminub), + DEFINE_OP(VMAXUB, 2, vmaxub), + DEFINE_OP(VMINSH, 2, vminsh), + DEFINE_OP(VMAXSH, 2, vmaxsh) +#undef DEFINE_OP + }; + + if (cpuinfo_check_sse()) { + for (int i = 0; i < sizeof(sse_vector) / sizeof(sse_vector[0]); i++) + jit_info[sse_vector[i].mnemo] = &sse_vector[i]; + } + + // generic altivec handlers + static const jit_info_t sse2_vector[] = { +#define DEFINE_OP(MNEMO, GEN_OP, DYNGEN_OP) \ + { PPC_I(MNEMO), (gen_handler_t)&powerpc_jit::gen_vector_generic_##GEN_OP, &powerpc_dyngen::gen_op_sse2_##DYNGEN_OP } + DEFINE_OP(VADDUBM, 2, vaddubm), + DEFINE_OP(VADDUHM, 2, vadduhm), + DEFINE_OP(VADDUWM, 2, vadduwm), + DEFINE_OP(VSUBUBM, 2, vsububm), + DEFINE_OP(VSUBUHM, 2, vsubuhm), + DEFINE_OP(VSUBUWM, 2, vsubuwm), + DEFINE_OP(VAND, 2, vand), + DEFINE_OP(VANDC, 2, vandc), + DEFINE_OP(VOR, 2, vor), + DEFINE_OP(VXOR, 2, vxor), + DEFINE_OP(VCMPEQUB, 2, vcmpequb), + DEFINE_OP(VCMPEQUH, 2, vcmpequh), + DEFINE_OP(VCMPEQUW, 2, vcmpequw), + DEFINE_OP(VCMPGTSB, 2, vcmpgtsb), + DEFINE_OP(VCMPGTSH, 2, vcmpgtsh), + DEFINE_OP(VCMPGTSW, 2, vcmpgtsw), +#undef DEFINE_OP + { PPC_I(VSLDOI), + (gen_handler_t)&powerpc_jit::gen_sse2_vsldoi, 0 } + }; + + if (cpuinfo_check_sse2()) { + for (int i = 0; i < sizeof(sse2_vector) / sizeof(sse2_vector[0]); i++) + jit_info[sse2_vector[i].mnemo] = &sse2_vector[i]; + } +#endif + } +} + +// Dispatch mid-level code generators +bool powerpc_jit::gen_vector_2(int mnemo, int vD, int vA, int vB, bool Rc) +{ + return (this->*((bool (powerpc_jit::*)(int, bool, int, int, int))jit_info[mnemo]->handler))(mnemo, Rc, vD, vA, vB); +} + +bool powerpc_jit::gen_vector_3(int mnemo, int vD, int vA, int vB, int vC, bool Rc) +{ + return (this->*((bool (powerpc_jit::*)(int, bool, int, int, int, int))jit_info[mnemo]->handler))(mnemo, Rc, vD, vA, vB, vC); +} + + +bool powerpc_jit::gen_not_available(int mnemo, bool Rc) +{ + return false; +} + +bool powerpc_jit::gen_vector_generic_2(int mnemo, bool Rc, int vD, int vA, int vB) +{ + gen_load_ad_VD_VR(vD); + gen_load_ad_V0_VR(vA); + gen_load_ad_V1_VR(vB); + jit_info[mnemo]->dyngen_handler(this); + if (Rc) + gen_record_cr6_VD(); + return true; +} + +bool powerpc_jit::gen_vector_generic_3(int mnemo, bool Rc, int vD, int vA, int vB, int vC) +{ + gen_load_ad_VD_VR(vD); + gen_load_ad_V0_VR(vA); + gen_load_ad_V1_VR(vB); + gen_load_ad_V2_VR(vC); + jit_info[mnemo]->dyngen_handler(this); + if (Rc) + gen_record_cr6_VD(); + return true; +} + +bool powerpc_jit::gen_vector_mmx_2(int mnemo, bool Rc, int vD, int vA, int vB) +{ +#if defined(__i386__) || defined(__x86_64__) + gen_load_ad_VD_VR(vD); + gen_load_ad_V0_VR(vA); + gen_load_ad_V1_VR(vB); + jit_info[mnemo]->dyngen_handler(this); + if (Rc) + gen_record_cr6_VD(); + gen_op_emms(); + return true; +#endif + return false; +} + +bool powerpc_jit::gen_sse2_vsldoi(int mnemo, bool Rc, int vD, int vA, int vB, int SH) +{ +#if defined(__i386__) || defined(__x86_64__) + gen_load_ad_VD_VR(vD); + gen_load_ad_V0_VR(vA); + if (SH == 0) + gen_op_sse_mov_VD_V0(); + else { + gen_load_ad_V1_VR(vB); + powerpc_dyngen::gen_sse2_vsldoi_VD_V0_V1(SH); + } + return true; +#endif + return false; +} diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.hpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.hpp new file mode 100644 index 00000000..b779b2dd --- /dev/null +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.hpp @@ -0,0 +1,54 @@ +/* + * ppc-jit.hpp - PowerPC dynamic translation (mid-level) + * + * Kheperix (C) 2003-2005 Gwenole Beauchesne + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PPC_JIT_H +#define PPC_JIT_H + +#include "sysdeps.h" +#include "cpu/ppc/ppc-dyngen.hpp" + +struct powerpc_jit + : public powerpc_dyngen +{ + // Default constructor + powerpc_jit(dyngen_cpu_base cpu, int cache_size = -1); + + bool gen_vector_2(int mnemo, int vD, int vA, int vB, bool Rc = false); + bool gen_vector_3(int mnemo, int vD, int vA, int vB, int vC, bool Rc = false); + +private: + // Mid-level code generator info + typedef bool (powerpc_jit::*gen_handler_t)(int, bool); + struct jit_info_t { + int mnemo; + gen_handler_t handler; + powerpc_dyngen::gen_handler_t dyngen_handler; + }; + static const jit_info_t *jit_info[]; + +private: + bool gen_not_available(int mnemo, bool Rc); + bool gen_vector_generic_2(int mnemo, bool Rc, int vD, int vA, int vB); + bool gen_vector_generic_3(int mnemo, bool Rc, int vD, int vA, int vB, int vC); + bool gen_vector_mmx_2(int mnemo, bool Rc, int vD, int vA, int vB); + bool gen_sse2_vsldoi(int mnemo, bool Rc, int vD, int vA, int vB, int SH); +}; + +#endif /* PPC_JIT_H */ diff --git a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-translate.cpp b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-translate.cpp index d0de90be..7826a904 100644 --- a/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-translate.cpp +++ b/SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-translate.cpp @@ -139,7 +139,7 @@ powerpc_cpu::compile_block(uint32 entry_point) clock_t start_time = clock(); #endif - powerpc_dyngen & dg = codegen; + powerpc_jit & dg = codegen; codegen_context_t cg_context(dg); cg_context.entry_point = entry_point; again: @@ -1397,26 +1397,16 @@ powerpc_cpu::compile_block(uint32 entry_point) dg.gen_mtvscr_V0(); break; } -#if defined(__i386__) || defined(__x86_64__) case PPC_I(VSLDOI): { const int vD = vD_field::extract(opcode); const int vA = vA_field::extract(opcode); const int vB = vB_field::extract(opcode); const int SH = vSH_field::extract(opcode); - if (dg.gen_vector_shift_octet(vD, vA, vB, SH)) - break; - // fall through + if (!dg.gen_vector_3(ii->mnemo, vD, vA, vB, SH)) + goto do_generic; + break; } -#endif - case PPC_I(VADDFP): - case PPC_I(VADDUBM): - case PPC_I(VADDUHM): - case PPC_I(VADDUWM): - case PPC_I(VAND): - case PPC_I(VANDC): - case PPC_I(VAVGUB): - case PPC_I(VAVGUH): case PPC_I(VCMPEQFP): case PPC_I(VCMPEQUB): case PPC_I(VCMPEQUH): @@ -1426,12 +1416,26 @@ powerpc_cpu::compile_block(uint32 entry_point) case PPC_I(VCMPGTSB): case PPC_I(VCMPGTSH): case PPC_I(VCMPGTSW): - case PPC_I(VMADDFP): + { + const int vD = vD_field::extract(opcode); + const int vA = vA_field::extract(opcode); + const int vB = vB_field::extract(opcode); + if (!dg.gen_vector_2(ii->mnemo, vD, vA, vB, vRc_field::test(opcode))) + goto do_generic; + break; + } + case PPC_I(VADDFP): + case PPC_I(VADDUBM): + case PPC_I(VADDUHM): + case PPC_I(VADDUWM): + case PPC_I(VAND): + case PPC_I(VANDC): + case PPC_I(VAVGUB): + case PPC_I(VAVGUH): case PPC_I(VMAXSH): case PPC_I(VMAXUB): case PPC_I(VMINSH): case PPC_I(VMINUB): - case PPC_I(VNMSUBFP): case PPC_I(VNOR): case PPC_I(VOR): case PPC_I(VSUBFP): @@ -1440,41 +1444,22 @@ powerpc_cpu::compile_block(uint32 entry_point) case PPC_I(VSUBUWM): case PPC_I(VXOR): { - powerpc_dyngen::gen_handler_t gen_op = 0; -#if defined(__i386__) || defined(__x86_64__) - /* XXX: analyze the block function */ - bool mmx_used = false; - - if ((gen_op = dg.vector_codegen_sse2(ii->mnemo)).ptr()) { - /* SSE2 code generator available */ - } - else if ((gen_op = dg.vector_codegen_sse(ii->mnemo)).ptr()) { - /* SSE code generator available */ - } - else if ((gen_op = dg.vector_codegen_mmx(ii->mnemo)).ptr()) { - /* MMX code generator available */ - mmx_used = true; - } - else -#endif - gen_op = dg.vector_codegen(ii->mnemo); - - if (!gen_op.ptr()) + const int vD = vD_field::extract(opcode); + const int vA = vA_field::extract(opcode); + const int vB = vB_field::extract(opcode); + if (!dg.gen_vector_2(ii->mnemo, vD, vA, vB)) + goto do_generic; + break; + } + case PPC_I(VMADDFP): + case PPC_I(VNMSUBFP): + { + const int vD = vD_field::extract(opcode); + const int vA = vA_field::extract(opcode); + const int vB = vB_field::extract(opcode); + const int vC = vC_field::extract(opcode); + if (!dg.gen_vector_3(ii->mnemo, vD, vA, vB, vC)) goto do_generic; - - dg.gen_load_ad_VD_VR(vD_field::extract(opcode)); - dg.gen_load_ad_V0_VR(vA_field::extract(opcode)); - dg.gen_load_ad_V1_VR(vB_field::extract(opcode)); - if (ii->format == VA_form) - dg.gen_load_ad_V2_VR(vC_field::extract(opcode)); - gen_op(&dg); - if (ii->format == VXR_form && vRc_field::test(opcode)) - dg.gen_record_cr6_VD(); - -#if defined(__i386__) || defined(__x86_64__) - if (mmx_used) - dg.gen_mmx_clear(); -#endif break; } default: // Direct call to instruction handler