first part of CR caching fixes

This commit is contained in:
gbeauche 2003-11-28 22:11:59 +00:00
parent ea0d909ce5
commit 0301afb3eb
3 changed files with 125 additions and 214 deletions

View File

@ -36,16 +36,7 @@ register struct powerpc_cpu *CPU asm(REG_CPU);
register uint32 A0 asm(REG_A0); register uint32 A0 asm(REG_A0);
register uint32 T0 asm(REG_T0); register uint32 T0 asm(REG_T0);
register uint32 T1 asm(REG_T1); register uint32 T1 asm(REG_T1);
#ifdef REG_T2 register uint32 RC asm(REG_T2);
register uint32 CC_LHS asm(REG_T2);
#else
#define CC_LHS powerpc_dyngen_helper::cc_lhs()
#endif
#ifdef REG_T3
register uint32 CC_RHS asm(REG_T3);
#else
#define CC_RHS powerpc_dyngen_helper::cc_rhs()
#endif
// Semantic action templates // Semantic action templates
#define DYNGEN_OPS #define DYNGEN_OPS
@ -71,8 +62,6 @@ struct powerpc_dyngen_helper {
static inline void record(int crf, int32 v) { CPU->record_cr(crf, v); } static inline void record(int crf, int32 v) { CPU->record_cr(crf, v); }
static inline powerpc_cr_register & cr() { return CPU->cr(); } static inline powerpc_cr_register & cr() { return CPU->cr(); }
static inline powerpc_xer_register & xer() { return CPU->xer(); } static inline powerpc_xer_register & xer() { return CPU->xer(); }
static inline uint32 & cc_lhs() { return CPU->codegen_ptr()->rc_cache.cc_lhs; }
static inline uint32 & cc_rhs() { return CPU->codegen_ptr()->rc_cache.cc_rhs; }
}; };
@ -206,79 +195,43 @@ DEFINE_REG(31);
#undef DEFINE_REG #undef DEFINE_REG
#undef DEFINE_OP #undef DEFINE_OP
#define DEFINE_OP(CRF, REG) \ #define DEFINE_OP(CRF, REG) \
void OPPROTO op_load_##REG##_cr##CRF(void) \ void OPPROTO op_load_##REG##_cr##CRF(void) \
{ \ { \
T0 = powerpc_dyngen_helper::cr().get(CRF); \ REG = powerpc_dyngen_helper::cr().get(CRF); \
} \ } \
void OPPROTO op_store_##REG##_cr##CRF(void) \ void OPPROTO op_store_##REG##_cr##CRF(void) \
{ \ { \
powerpc_dyngen_helper::cr().set(CRF, REG); \ powerpc_dyngen_helper::cr().set(CRF, REG); \
} \
void OPPROTO op_commit_so_cache_cr##CRF(void) \
{ \
uint32 cr = powerpc_dyngen_helper::get_cr(); \
const uint32 cr_mask = CR_SO_field<CRF>::mask(); \
cr = (cr & ~cr_mask) | ((RC << (28 - 4 * CRF)) & cr_mask); \
powerpc_dyngen_helper::set_cr(cr); \
} \
void OPPROTO op_commit_rc_cache_cr##CRF(void) \
{ \
uint32 cr = powerpc_dyngen_helper::get_cr(); \
const uint32 cr_mask = (CR_LT_field<CRF>::mask() | \
CR_GT_field<CRF>::mask() | \
CR_EQ_field<CRF>::mask()); \
cr = (cr & ~cr_mask) | ((RC << (28 - 4 * CRF)) & cr_mask); \
powerpc_dyngen_helper::set_cr(cr); \
} }
DEFINE_OP(0, T0); DEFINE_OP(0, RC);
DEFINE_OP(1, T0); DEFINE_OP(1, RC);
DEFINE_OP(2, T0); DEFINE_OP(2, RC);
DEFINE_OP(3, T0); DEFINE_OP(3, RC);
DEFINE_OP(4, T0); DEFINE_OP(4, RC);
DEFINE_OP(5, T0); DEFINE_OP(5, RC);
DEFINE_OP(6, T0); DEFINE_OP(6, RC);
DEFINE_OP(7, T0); DEFINE_OP(7, RC);
#undef DEFINE_OP #undef DEFINE_OP
#define DEFINE_OP(CRF) \
void OPPROTO op_commit_so_cache_cr##CRF(void) \
{ \
int so = powerpc_dyngen_helper::xer().get_so(); \
powerpc_dyngen_helper::cr().set_so(CRF, so); \
}
DEFINE_OP(0);
DEFINE_OP(1);
DEFINE_OP(2);
DEFINE_OP(3);
DEFINE_OP(4);
DEFINE_OP(5);
DEFINE_OP(6);
DEFINE_OP(7);
#undef DEFINE_OP
#define DEFINE_OP_1(NAME,TYPE,CRF) \
void OPPROTO op_##NAME##_rc_cache_cr##CRF(void) \
{ \
uint32 cr = powerpc_dyngen_helper::get_cr(); \
cr &= ~(CR_LT_field<CRF>::mask() | \
CR_GT_field<CRF>::mask() | \
CR_EQ_field<CRF>::mask()); \
\
if ((TYPE)CC_LHS < (TYPE)CC_RHS) \
cr |= CR_LT_field<CRF>::mask(); \
else if ((TYPE)CC_LHS > (TYPE)CC_RHS) \
cr |= CR_GT_field<CRF>::mask(); \
else \
cr |= CR_EQ_field<CRF>::mask(); \
\
powerpc_dyngen_helper::set_cr(cr); \
dyngen_barrier(); \
}
#define DEFINE_OP(CRF) \
DEFINE_OP_1(commit,int32,CRF); \
DEFINE_OP_1(commit_logical,uint32,CRF)
DEFINE_OP(0);
DEFINE_OP(1);
DEFINE_OP(2);
DEFINE_OP(3);
DEFINE_OP(4);
DEFINE_OP(5);
DEFINE_OP(6);
DEFINE_OP(7);
#undef DEFINE_OP
#undef DEFINE_OP_1
/** /**
* Special purpose registers * Special purpose registers
@ -394,9 +347,9 @@ static inline void do_execute_branch(uint32 tpc, uint32 npc)
} }
template< int crb > template< int crb >
struct CR_comparator { struct RC_comparator {
static inline bool test() { static inline bool test() {
return (T0 & crb); return (RC & crb);
} }
}; };
@ -414,14 +367,14 @@ struct bool_condition< false, comparator > {
} }
}; };
typedef bool_condition< true, CR_comparator<8> > blt_condition; typedef bool_condition< true, RC_comparator<8> > blt_condition;
typedef bool_condition<false, CR_comparator<8> > bnlt_condition; typedef bool_condition<false, RC_comparator<8> > bnlt_condition;
typedef bool_condition< true, CR_comparator<4> > bgt_condition; typedef bool_condition< true, RC_comparator<4> > bgt_condition;
typedef bool_condition<false, CR_comparator<4> > bngt_condition; typedef bool_condition<false, RC_comparator<4> > bngt_condition;
typedef bool_condition< true, CR_comparator<2> > beq_condition; typedef bool_condition< true, RC_comparator<2> > beq_condition;
typedef bool_condition<false, CR_comparator<2> > bneq_condition; typedef bool_condition<false, RC_comparator<2> > bneq_condition;
typedef bool_condition< true, CR_comparator<1> > bso_condition; typedef bool_condition< true, RC_comparator<1> > bso_condition;
typedef bool_condition<false, CR_comparator<1> > bnso_condition; typedef bool_condition<false, RC_comparator<1> > bnso_condition;
struct ctr_0x_condition { struct ctr_0x_condition {
static inline bool test() { static inline bool test() {
@ -453,7 +406,7 @@ void OPPROTO op_##COND##_##CTR(void) \
#define DEFINE_OP(COND) \ #define DEFINE_OP(COND) \
DEFINE_OP_CTR(COND,0x); \ DEFINE_OP_CTR(COND,0x); \
DEFINE_OP_CTR(COND,10); \ DEFINE_OP_CTR(COND,10); \
DEFINE_OP_CTR(COND,11) DEFINE_OP_CTR(COND,11);
DEFINE_OP(blt); DEFINE_OP(blt);
DEFINE_OP(bgt); DEFINE_OP(bgt);
@ -478,52 +431,9 @@ void OPPROTO op_record_nego_T0(void)
dyngen_barrier(); dyngen_barrier();
} }
void OPPROTO op_record_cr0_T0(void)
{
uint32 cr = powerpc_dyngen_helper::get_cr();
cr &= ~(CR_LT_field<0>::mask() |
CR_GT_field<0>::mask() |
CR_EQ_field<0>::mask() |
CR_SO_field<0>::mask());
#if DYNGEN_ASM_OPTS
#if defined(__powerpc__)
uint32 v;
asm volatile ("cmpwi 0,%1,0 ; mfcr %0" : "=r" (v) : "r" (T0) : "cr0");
cr |= (v & (0xe0000000));
cr |= (powerpc_dyngen_helper::xer().get_so() << (31 - 3));
goto end;
#endif
#endif
if (powerpc_dyngen_helper::xer().get_so())
cr |= CR_SO_field<0>::mask();
if ((int32)T0 < 0)
cr |= CR_LT_field<0>::mask();
else if ((int32)T0 > 0)
cr |= CR_GT_field<0>::mask();
else
cr |= CR_EQ_field<0>::mask();
end:
powerpc_dyngen_helper::set_cr(cr);
dyngen_barrier();
}
#define im PARAM1 #define im PARAM1
#define DEFINE_OP(LHS, RHS) \ #if DYNGEN_ASM_OPTS && defined(__powerpc__) && 0
void OPPROTO op_compare_##LHS##_##RHS(void) \
{ \
CC_LHS = LHS; \
CC_RHS = RHS; \
}
DEFINE_OP(T0,T1);
DEFINE_OP(T0,im);
DEFINE_OP(T0,0);
#undef DEFINE_OP
#if DYNGEN_ASM_OPTS && defined(__powerpc__)
#define DEFINE_OP(NAME, COMP, LHS, RHST, RHS) \ #define DEFINE_OP(NAME, COMP, LHS, RHST, RHS) \
void OPPROTO op_##NAME##_##LHS##_##RHS(void) \ void OPPROTO op_##NAME##_##LHS##_##RHS(void) \
@ -543,26 +453,25 @@ DEFINE_OP(do_compare_logical,"cmplwi",T0,"i",0);
#else #else
#define DEFINE_OP(NAME, TYPE, LHS, RHS) \ #define DEFINE_OP(NAME, TYPE, LHS, RHS) \
void OPPROTO op_##NAME##_##LHS##_##RHS(void) \ void OPPROTO op_##NAME##_##LHS##_##RHS(void) \
{ \ { \
uint32 cr = powerpc_dyngen_helper::xer().get_so(); \ RC = powerpc_dyngen_helper::xer().get_so(); \
if ((TYPE)LHS < (TYPE)RHS) \ if ((TYPE)LHS < (TYPE)RHS) \
cr |= standalone_CR_LT_field::mask(); \ RC |= standalone_CR_LT_field::mask(); \
else if ((TYPE)LHS > (TYPE)RHS) \ else if ((TYPE)LHS > (TYPE)RHS) \
cr |= standalone_CR_GT_field::mask(); \ RC |= standalone_CR_GT_field::mask(); \
else \ else \
cr |= standalone_CR_EQ_field::mask(); \ RC |= standalone_CR_EQ_field::mask(); \
T0 = cr; \ dyngen_barrier(); \
dyngen_barrier(); \
} }
DEFINE_OP(do_compare,int32,T0,T1); DEFINE_OP(compare,int32,T0,T1);
DEFINE_OP(do_compare,int32,T0,im); DEFINE_OP(compare,int32,T0,im);
DEFINE_OP(do_compare,int32,T0,0); DEFINE_OP(compare,int32,T0,0);
DEFINE_OP(do_compare_logical,uint32,T0,T1); DEFINE_OP(compare_logical,uint32,T0,T1);
DEFINE_OP(do_compare_logical,uint32,T0,im); DEFINE_OP(compare_logical,uint32,T0,im);
DEFINE_OP(do_compare_logical,uint32,T0,0); DEFINE_OP(compare_logical,uint32,T0,0);
#endif #endif

View File

@ -31,51 +31,44 @@
void powerpc_dyngen::invalidate_so_cache() void powerpc_dyngen::invalidate_so_cache()
{ {
rc_cache.so_status = RC_cache::STATUS_TRASH; rc_cache.set_so_status(RC_cache::STATUS_TRASH);
} }
void powerpc_dyngen::invalidate_cr_cache() void powerpc_dyngen::invalidate_cr_cache()
{ {
invalidate_so_cache(); invalidate_so_cache();
rc_cache.val_status = RC_cache::STATUS_TRASH; rc_cache.set_val_status(RC_cache::STATUS_TRASH);
rc_cache.crf = -1; rc_cache.set_crf(-1);
}
void powerpc_dyngen::do_gen_commit_cr()
{
gen_commit_so();
switch (rc_cache.val_status) {
case RC_cache::STATUS_VALID:
gen_commit_rc_cache_cr(rc_cache.crf);
break;
case RC_cache::STATUS_VALID_LOGICAL:
gen_commit_logical_rc_cache_cr(rc_cache.crf);
break;
default:
abort();
}
invalidate_cr_cache();
}
void powerpc_dyngen::do_gen_commit_so()
{
gen_commit_so_cache_cr(rc_cache.crf);
invalidate_so_cache();
} }
void powerpc_dyngen::gen_commit_cr() void powerpc_dyngen::gen_commit_cr()
{ {
if (rc_cache.val_status != RC_cache::STATUS_TRASH) { if (rc_cache.val_status() == RC_cache::STATUS_VALID &&
assert(rc_cache.crf != -1); rc_cache.so_status() == RC_cache::STATUS_VALID) {
do_gen_commit_cr(); const int crf = rc_cache.crf();
assert(crf != -1);
gen_store_RC_cr(crf);
invalidate_cr_cache();
}
else if (rc_cache.val_status() == RC_cache::STATUS_VALID) {
const int crf = rc_cache.crf();
assert(crf != -1);
gen_commit_rc_cache_cr(crf);
invalidate_cr_cache();
}
else {
// Maybe only SO field left to spill
gen_commit_so();
} }
} }
void powerpc_dyngen::gen_commit_so() void powerpc_dyngen::gen_commit_so()
{ {
if (rc_cache.so_status != RC_cache::STATUS_TRASH) { if (rc_cache.so_status() == RC_cache::STATUS_VALID) {
assert(rc_cache.crf != -1); const int crf = rc_cache.crf();
do_gen_commit_so(); assert(crf != -1);
gen_commit_so_cache_cr(crf);
invalidate_so_cache();
} }
} }
@ -102,8 +95,8 @@ void powerpc_dyngen::gen_compare_logical_T0_T1(int crf)
{ {
if (!rc_cache.has_field(crf)) if (!rc_cache.has_field(crf))
gen_commit_cr(); gen_commit_cr();
gen_op_compare_T0_T1(); gen_op_compare_logical_T0_T1();
rc_cache.cache_field(crf, RC_cache::STATUS_VALID_LOGICAL); rc_cache.cache_field(crf);
} }
void powerpc_dyngen::gen_compare_logical_T0_im(int crf, int32 value) void powerpc_dyngen::gen_compare_logical_T0_im(int crf, int32 value)
@ -111,10 +104,10 @@ void powerpc_dyngen::gen_compare_logical_T0_im(int crf, int32 value)
if (!rc_cache.has_field(crf)) if (!rc_cache.has_field(crf))
gen_commit_cr(); gen_commit_cr();
if (value == 0) if (value == 0)
gen_op_compare_T0_0(); gen_op_compare_logical_T0_0();
else else
gen_op_compare_T0_im(value); gen_op_compare_logical_T0_im(value);
rc_cache.cache_field(crf, RC_cache::STATUS_VALID_LOGICAL); rc_cache.cache_field(crf);
} }
/** /**
@ -193,11 +186,10 @@ void powerpc_dyngen::gen_##OP##_##REG##_cr(int crf) \
} \ } \
} }
DEFINE_INSN(load, T0); DEFINE_INSN(load, RC);
DEFINE_INSN(store, T0); DEFINE_INSN(store, RC);
DEFINE_INSN(commit, so_cache); DEFINE_INSN(commit, so_cache);
DEFINE_INSN(commit, rc_cache); DEFINE_INSN(commit, rc_cache);
DEFINE_INSN(commit_logical, rc_cache);
#undef DEFINE_INSN #undef DEFINE_INSN
@ -206,12 +198,20 @@ void powerpc_dyngen::gen_record_cr0_T0(void)
gen_compare_T0_im(0, 0); gen_compare_T0_im(0, 0);
} }
void powerpc_dyngen::gen_prepare_RC(int bi)
{
const int crf = bi / 4;
const int crb = bi % 4;
gen_commit_cr();
gen_load_RC_cr(crf);
}
void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc) void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc)
{ {
gen_commit_cr();
if (BO_CONDITIONAL_BRANCH(bo)) { if (BO_CONDITIONAL_BRANCH(bo)) {
enum { lt, gt, eq, so }; enum { lt, gt, eq, so };
gen_load_T0_cr(bi / 4); gen_prepare_RC(bi);
const int n = ((bi % 4) << 2) | ((bo >> 1) & 3); const int n = ((bi % 4) << 2) | ((bo >> 1) & 3);
#define _(CR,DCTR,CTR0) (((CR) << 2) | ((DCTR) ? 0 : 2) | ((CTR0) ? 1 : 0)) #define _(CR,DCTR,CTR0) (((CR) << 2) | ((DCTR) ? 0 : 2) | ((CTR0) ? 1 : 0))
if (BO_BRANCH_IF_TRUE(bo)) { if (BO_BRANCH_IF_TRUE(bo)) {
@ -239,6 +239,7 @@ void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc)
#undef _ #undef _
} }
else { else {
gen_commit_cr();
if (BO_DECREMENT_CTR(bo)) { if (BO_DECREMENT_CTR(bo)) {
gen_decrement_ctr_T0(); gen_decrement_ctr_T0();
if (BO_BRANCH_IF_CTR_ZERO(bo)) if (BO_BRANCH_IF_CTR_ZERO(bo))

View File

@ -37,30 +37,33 @@ class powerpc_dyngen
# include "ppc-dyngen-ops.hpp" # include "ppc-dyngen-ops.hpp"
#endif #endif
struct RC_cache { class RC_cache {
int m_val_status;
int m_so_status;
int m_crf;
public:
int crf() const { return m_crf; }
int val_status() const { return m_val_status; }
int so_status() const { return m_so_status; }
void set_crf(int v) { m_crf = v; }
void set_val_status(int v) { m_val_status = v; }
void set_so_status(int v) { m_so_status = v; }
enum { enum {
STATUS_TRASH, STATUS_TRASH,
STATUS_VALID, STATUS_VALID,
STATUS_VALID_LOGICAL
}; };
int val_status;
int so_status;
int crf;
// Used only by generated code if not enough native registers
// are available to cache them all
uint32 cc_lhs;
uint32 cc_rhs;
RC_cache() RC_cache()
: val_status(STATUS_TRASH), so_status(STATUS_TRASH), crf(-1) : m_val_status(STATUS_TRASH), m_so_status(STATUS_TRASH), m_crf(-1)
{ } { }
bool has_field(int test_crf) bool has_field(int crf) const
{ return val_status != STATUS_TRASH && crf == test_crf; } { return m_crf == crf; }
void cache_field(int new_crf, int new_status = STATUS_VALID) void cache_field(int crf)
{ val_status = so_status = new_status; crf = new_crf; } { m_val_status = m_so_status = STATUS_VALID; m_crf = crf; }
}; };
RC_cache rc_cache; RC_cache rc_cache;
@ -102,11 +105,8 @@ public:
// Condition registers // Condition registers
private: private:
void do_gen_commit_so();
void do_gen_commit_cr();
void gen_commit_so_cache_cr(int crf); void gen_commit_so_cache_cr(int crf);
void gen_commit_rc_cache_cr(int crf); void gen_commit_rc_cache_cr(int crf);
void gen_commit_logical_rc_cache_cr(int crf);
public: public:
void invalidate_so_cache(); void invalidate_so_cache();
void invalidate_cr_cache(); void invalidate_cr_cache();
@ -120,8 +120,9 @@ public:
void gen_load_T1_crb(int i); void gen_load_T1_crb(int i);
void gen_store_T0_crb(int i); void gen_store_T0_crb(int i);
void gen_store_T1_crb(int i); void gen_store_T1_crb(int i);
void gen_load_T0_cr(int crf); void gen_load_RC_cr(int crf);
void gen_store_T0_cr(int crf); void gen_store_RC_cr(int crf);
void gen_prepare_RC(int bi);
// Special purpose registers // Special purpose registers
DEFINE_ALIAS(load_T0_PC,0); DEFINE_ALIAS(load_T0_PC,0);