Prepare for new code generator and mid-level optimizations.

This commit is contained in:
gbeauche 2006-07-16 12:47:38 +00:00
parent 7cfee5a2be
commit cc12787047
8 changed files with 358 additions and 307 deletions

View File

@ -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)

View File

@ -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"

View File

@ -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);

View File

@ -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
}

View File

@ -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

View 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;
}

View 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 */

View File

@ -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