Cleanups. Rewrite gen_bc() so that no push/pop could be inserted thus

causing crahes with some compilers. However, that's slower.
This commit is contained in:
gbeauche 2004-06-09 16:36:44 +00:00
parent 301d3a3192
commit f574a5df05
4 changed files with 128 additions and 183 deletions

View File

@ -600,90 +600,6 @@ void OPPROTO op_spcflags_clear(void)
* Branch instructions
**/
void OPPROTO op_decrement_ctr_T0(void)
{
T0 = powerpc_dyngen_helper::get_ctr() - 1;
powerpc_dyngen_helper::set_ctr(T0);
}
void OPPROTO op_branch_A0_if_T0(void)
{
if (T0)
powerpc_dyngen_helper::set_pc(A0);
else
powerpc_dyngen_helper::set_pc(PARAM1);
dyngen_barrier();
}
void OPPROTO op_branch_A0_if_not_T0(void)
{
if (!T0)
powerpc_dyngen_helper::set_pc(A0);
else
powerpc_dyngen_helper::set_pc(PARAM1);
dyngen_barrier();
}
template< class branch_cond, class ctr_cond >
static inline void do_execute_branch(uint32 tpc, uint32 npc)
{
if (branch_cond::test() && ctr_cond::test())
powerpc_dyngen_helper::set_pc(tpc);
else
powerpc_dyngen_helper::set_pc(npc);
dyngen_barrier();
}
struct branch_if_T0_condition {
static inline bool test() {
return T0 != 0;
}
};
struct branch_if_not_T0_condition {
static inline bool test() {
return T0 == 0;
}
};
struct ctr_0x_condition {
static inline bool test() {
return true;
}
};
struct ctr_10_condition {
static inline bool test() {
uint32 ctr = powerpc_dyngen_helper::get_ctr() - 1;
powerpc_dyngen_helper::set_ctr(ctr);
return ctr != 0;
}
};
struct ctr_11_condition {
static inline bool test() {
uint32 ctr = powerpc_dyngen_helper::get_ctr() - 1;
powerpc_dyngen_helper::set_ctr(ctr);
return ctr == 0;
}
};
#define DEFINE_OP_CTR(COND,CTR) \
void OPPROTO op_##COND##_ctr_##CTR(void) \
{ \
do_execute_branch<COND##_condition, ctr_##CTR##_condition>(A0, PARAM1); \
}
#define DEFINE_OP(COND) \
DEFINE_OP_CTR(COND,0x); \
DEFINE_OP_CTR(COND,10); \
DEFINE_OP_CTR(COND,11);
DEFINE_OP(branch_if_T0);
DEFINE_OP(branch_if_not_T0);
#undef DEFINE_OP
#undef DEFINE_OP_CTR
#ifdef DYNGEN_FAST_DISPATCH
#if defined(__x86_64__)
#define FAST_COMPARE_SPECFLAGS_DISPATCH(SPCFLAGS, TARGET) \
@ -695,8 +611,8 @@ DEFINE_OP(branch_if_not_T0);
#endif
#endif
template< int bo, bool chain >
static inline void do_execute_branch_bo(uint32 tpc, uint32 npc)
template< int bo >
static inline void do_prep_branch_bo(void)
{
bool ctr_ok = true;
bool cond_ok = true;
@ -712,40 +628,21 @@ static inline void do_execute_branch_bo(uint32 tpc, uint32 npc)
T1 = powerpc_dyngen_helper::get_ctr() - 1;
powerpc_dyngen_helper::set_ctr(T1);
if (BO_BRANCH_IF_CTR_ZERO(bo))
ctr_ok = T1 == 0;
ctr_ok = !T1;
else
ctr_ok = T1 != 0;
ctr_ok = T1;
}
#ifdef DYNGEN_FAST_DISPATCH
if (chain) {
T1 = powerpc_dyngen_helper::spcflags().get();
if (ctr_ok && cond_ok) {
FAST_COMPARE_SPECFLAGS_DISPATCH(T1, __op_jmp0);
T0 = tpc;
}
else {
FAST_COMPARE_SPECFLAGS_DISPATCH(T1, __op_jmp1);
T0 = npc;
}
}
else
#endif
T0 = (ctr_ok && cond_ok) ? tpc : npc;
powerpc_dyngen_helper::set_pc(T0);
T0 = ctr_ok && cond_ok;
dyngen_barrier();
}
#define BO(A,B,C,D) (((A) << 4)| ((B) << 3) | ((C) << 2) | ((D) << 1))
#define DEFINE_OP1(BO_SUFFIX, BO_VALUE, CHAIN) \
void OPPROTO op_branch_A0_bo_##BO_SUFFIX##_##CHAIN(void) \
{ \
do_execute_branch_bo<BO BO_VALUE, CHAIN>(A0, PARAM1); \
#define DEFINE_OP(BO_SUFFIX, BO_VALUE) \
void OPPROTO op_prep_branch_bo_##BO_SUFFIX(void) \
{ \
do_prep_branch_bo<BO BO_VALUE>(); \
}
#define DEFINE_OP(BO_SUFFIX, BO_VALUE) \
DEFINE_OP1(BO_SUFFIX, BO_VALUE, 0) \
DEFINE_OP1(BO_SUFFIX, BO_VALUE, 1)
DEFINE_OP(0000,(0,0,0,0));
DEFINE_OP(0001,(0,0,0,1));
@ -761,6 +658,80 @@ DEFINE_OP(1x1x,(1,0,1,0));
#undef DEFINE_OP
#undef BO
template< bool chain >
static inline void do_execute_branch_1(uint32 tpc)
{
#ifdef DYNGEN_FAST_DISPATCH
if (chain)
FAST_COMPARE_SPECFLAGS_DISPATCH(powerpc_dyngen_helper::spcflags().get(), __op_jmp0);
#endif
powerpc_dyngen_helper::set_pc(tpc);
dyngen_barrier();
}
void op_branch_1_A0(void)
{
do_execute_branch_1<0>(A0);
}
void op_branch_chain_1_A0(void)
{
do_execute_branch_1<1>(A0);
}
void op_branch_1_im(void)
{
do_execute_branch_1<0>(PARAM1);
}
void op_branch_chain_1_im(void)
{
do_execute_branch_1<1>(PARAM1);
}
template< bool chain >
static inline void do_execute_branch_2(uint32 tpc, uint32 npc)
{
#ifdef DYNGEN_FAST_DISPATCH
if (chain) {
T1 = powerpc_dyngen_helper::spcflags().get();
if (T0) {
FAST_COMPARE_SPECFLAGS_DISPATCH(T1, __op_jmp0);
A0 = tpc;
}
else {
FAST_COMPARE_SPECFLAGS_DISPATCH(T1, __op_jmp1);
A0 = npc;
}
}
else
#endif
A0 = T0 ? tpc : npc;
powerpc_dyngen_helper::set_pc(A0);
dyngen_barrier();
}
void op_branch_2_A0_im(void)
{
do_execute_branch_2<0>(A0, PARAM1);
}
void op_branch_chain_2_A0_im(void)
{
do_execute_branch_2<1>(A0, PARAM1);
}
void op_branch_2_im_im(void)
{
do_execute_branch_2<0>(PARAM1, PARAM2);
}
void op_branch_chain_2_im_im(void)
{
do_execute_branch_2<1>(PARAM1, PARAM2);
}
/**
* Compare & Record instructions

View File

@ -260,91 +260,65 @@ DEFINE_INSN(store, T0);
#undef DEFINE_INSN
void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc, bool direct_chaining)
void powerpc_dyngen::gen_bc(int bo, int bi, uint32 tpc, uint32 npc, bool direct_chaining)
{
#if 1
if (BO_CONDITIONAL_BRANCH(bo)) {
gen_load_T0_CR();
gen_and_32_T0_im(1 << (31 - bi));
}
if (direct_chaining) {
switch (bo >> 1) {
#define _(A,B,C,D) (((A) << 3)| ((B) << 2) | ((C) << 1) | (D))
case _(0,0,0,0): gen_op_branch_A0_bo_0000_1(npc); break;
case _(0,0,0,1): gen_op_branch_A0_bo_0001_1(npc); break;
case _(0,0,0,0): gen_op_prep_branch_bo_0000(); break;
case _(0,0,0,1): gen_op_prep_branch_bo_0001(); break;
case _(0,0,1,0):
case _(0,0,1,1): gen_op_branch_A0_bo_001x_1(npc); break;
case _(0,1,0,0): gen_op_branch_A0_bo_0100_1(npc); break;
case _(0,1,0,1): gen_op_branch_A0_bo_0101_1(npc); break;
case _(0,0,1,1): gen_op_prep_branch_bo_001x(); break;
case _(0,1,0,0): gen_op_prep_branch_bo_0100(); break;
case _(0,1,0,1): gen_op_prep_branch_bo_0101(); break;
case _(0,1,1,0):
case _(0,1,1,1): gen_op_branch_A0_bo_011x_1(npc); break;
case _(0,1,1,1): gen_op_prep_branch_bo_011x(); break;
case _(1,0,0,0):
case _(1,1,0,0): gen_op_branch_A0_bo_1x00_1(npc); break;
case _(1,1,0,0): gen_op_prep_branch_bo_1x00(); break;
case _(1,0,0,1):
case _(1,1,0,1): gen_op_branch_A0_bo_1x01_1(npc); break;
case _(1,1,0,1): gen_op_prep_branch_bo_1x01(); break;
case _(1,0,1,0):
case _(1,0,1,1):
case _(1,1,1,0):
case _(1,1,1,1): gen_op_branch_A0_bo_1x1x_1(); break;
case _(1,1,1,1): gen_op_prep_branch_bo_1x1x(); break;
#undef _
default: abort();
}
} else {
switch (bo >> 1) {
#define _(A,B,C,D) (((A) << 3)| ((B) << 2) | ((C) << 1) | (D))
case _(0,0,0,0): gen_op_branch_A0_bo_0000_0(npc); break;
case _(0,0,0,1): gen_op_branch_A0_bo_0001_0(npc); break;
case _(0,0,1,0):
case _(0,0,1,1): gen_op_branch_A0_bo_001x_0(npc); break;
case _(0,1,0,0): gen_op_branch_A0_bo_0100_0(npc); break;
case _(0,1,0,1): gen_op_branch_A0_bo_0101_0(npc); break;
case _(0,1,1,0):
case _(0,1,1,1): gen_op_branch_A0_bo_011x_0(npc); break;
case _(1,0,0,0):
case _(1,1,0,0): gen_op_branch_A0_bo_1x00_0(npc); break;
case _(1,0,0,1):
case _(1,1,0,1): gen_op_branch_A0_bo_1x01_0(npc); break;
case _(1,0,1,0):
case _(1,0,1,1):
case _(1,1,1,0):
case _(1,1,1,1): gen_op_branch_A0_bo_1x1x_0(); break;
#undef _
default: abort();
}
}
#else
if (BO_CONDITIONAL_BRANCH(bo)) {
gen_load_T0_CR();
gen_and_32_T0_im(1 << (31 - bi));
const int n = (bo >> 1) & 7;
switch (n) {
#define _(TRUE,DCTR,CTR0) (((TRUE) ? 4 : 0) | ((DCTR) ? 0 : 2) | ((CTR0) ? 1 : 0))
case _(0,0,0): gen_op_branch_if_not_T0_ctr_0x(npc); break;
case _(0,0,1): gen_op_branch_if_not_T0_ctr_0x(npc); break;
case _(0,1,0): gen_op_branch_if_not_T0_ctr_10(npc); break;
case _(0,1,1): gen_op_branch_if_not_T0_ctr_11(npc); break;
case _(1,0,0): gen_op_branch_if_T0_ctr_0x(npc); break;
case _(1,0,1): gen_op_branch_if_T0_ctr_0x(npc); break;
case _(1,1,0): gen_op_branch_if_T0_ctr_10(npc); break;
case _(1,1,1): gen_op_branch_if_T0_ctr_11(npc); break;
#undef _
default: abort();
if (BO_CONDITIONAL_BRANCH(bo) || BO_DECREMENT_CTR(bo)) {
// two-way branches
if (tpc != 0xffffffff) {
if (direct_chaining)
gen_op_branch_chain_2_im_im(tpc, npc);
else
gen_op_branch_2_im_im(tpc, npc);
}
else {
if (direct_chaining)
gen_op_branch_chain_2_A0_im(npc);
else
gen_op_branch_2_A0_im(npc);
}
}
else {
if (BO_DECREMENT_CTR(bo)) {
gen_decrement_ctr_T0();
if (BO_BRANCH_IF_CTR_ZERO(bo))
gen_branch_A0_if_not_T0(npc);
// one-way branches
if (tpc != 0xffffffff) {
if (direct_chaining)
gen_op_branch_chain_1_im(tpc);
else
gen_branch_A0_if_T0(npc);
gen_op_branch_1_im(tpc);
}
else {
// Branch always
gen_set_PC_A0();
if (direct_chaining)
gen_op_branch_chain_1_A0();
else
gen_op_branch_1_A0();
}
}
#endif
}
/**

View File

@ -125,9 +125,6 @@ public:
DEFINE_ALIAS(spcflags_clear,1);
// Control Flow
DEFINE_ALIAS(decrement_ctr_T0,0);
DEFINE_ALIAS(branch_A0_if_T0,1);
DEFINE_ALIAS(branch_A0_if_not_T0,1);
DEFINE_ALIAS(jump_next_A0,0);
// Compare & Record instructions
@ -224,7 +221,7 @@ public:
void gen_store_single_F0_A0_im(int32 offset);
// Branch instructions
void gen_bc_A0(int bo, int bi, uint32 npc, bool direct_chaining);
void gen_bc(int bo, int bi, uint32 tpc, uint32 npc, bool direct_chaining);
// Vector instructions
void gen_load_ad_VD_VR(int i);

View File

@ -479,9 +479,9 @@ powerpc_cpu::compile_block(uint32 entry_point)
}
#endif
const uint32 tpc = ((AA_field::test(opcode) ? 0 : dpc) + operand_BD::get(this, opcode)) & -4;
const uint32 npc = dpc + 4;
#if DYNGEN_DIRECT_BLOCK_CHAINING
// Use direct block chaining for in-page jumps or jumps to ROM area
const uint32 npc = dpc + 4;
if (direct_chaining_possible(bi->pc, tpc)) {
use_direct_block_chaining = true;
bi->jmp_pc[0] = tpc;
@ -490,8 +490,12 @@ powerpc_cpu::compile_block(uint32 entry_point)
bi->jmp_pc[1] = npc;
}
#endif
dg.gen_mov_32_A0_im(tpc);
goto do_branch;
if (LK_field::test(opcode))
dg.gen_store_im_LR(npc);
dg.gen_bc(bo, BI_field::extract(opcode), tpc, npc, use_direct_block_chaining);
break;
}
case PPC_I(BCCTR): // Branch Conditional to Count Register
dg.gen_load_A0_CTR();
@ -508,7 +512,7 @@ powerpc_cpu::compile_block(uint32 entry_point)
if (LK_field::test(opcode))
dg.gen_store_im_LR(npc);
dg.gen_bc_A0(bo, bi, npc, use_direct_block_chaining);
dg.gen_bc(bo, bi, (uint32)-1, npc, use_direct_block_chaining);
break;
}
case PPC_I(B): // Branch
@ -546,10 +550,9 @@ powerpc_cpu::compile_block(uint32 entry_point)
bi->jmp_pc[0] = tpc;
}
#endif
dg.gen_mov_32_A0_im(tpc);
// BO field is built so that we always branch to A0
dg.gen_bc_A0(BO_MAKE(0,0,0,0), 0, 0, use_direct_block_chaining);
// BO field is built so that we always branch to pc
dg.gen_bc(BO_MAKE(0,0,0,0), 0, tpc, 0, use_direct_block_chaining);
break;
}
case PPC_I(CMP): // Compare