mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-06-27 16:29:29 +00:00
Prepare for new code generator and mid-level optimizations.
This commit is contained in:
parent
7cfee5a2be
commit
cc12787047
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 <vector>
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
if (cpuinfo_check_mmx())
|
||||
printf(" MMX");
|
||||
if (cpu_features & HWCAP_I386_SSE)
|
||||
if (cpuinfo_check_sse())
|
||||
printf(" SSE");
|
||||
if (cpu_features & HWCAP_I386_SSE2)
|
||||
if (cpuinfo_check_sse2())
|
||||
printf(" SSE2");
|
||||
if (cpu_features & HWCAP_I386_SSE3)
|
||||
if (cpuinfo_check_sse3())
|
||||
printf(" SSE3");
|
||||
if (cpu_features & HWCAP_I386_SSE4)
|
||||
if (cpuinfo_check_sse4())
|
||||
printf(" SSE4");
|
||||
if (cpuinfo_check_altivec())
|
||||
printf(" VMX");
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -370,122 +308,9 @@ 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) {
|
||||
#define GEN_OP(SH) case SH: gen_op_sse2_vsldoi_##SH(); break
|
||||
GEN_OP(1);
|
||||
|
@ -506,44 +331,5 @@ bool powerpc_dyngen::gen_vector_shift_octet(int vD, int vA, int vB, int SH)
|
|||
#undef GEN_OP
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
234
SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.cpp
Normal file
234
SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.cpp
Normal file
|
@ -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;
|
||||
}
|
54
SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.hpp
Normal file
54
SheepShaver/src/kpx_cpu/src/cpu/ppc/ppc-jit.hpp
Normal file
|
@ -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 */
|
|
@ -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))
|
||||
if (!dg.gen_vector_3(ii->mnemo, vD, vA, vB, SH))
|
||||
goto do_generic;
|
||||
break;
|
||||
// fall through
|
||||
}
|
||||
#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
|
||||
|
|
Loading…
Reference in New Issue
Block a user