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 T0 asm(REG_T0);
register uint32 T1 asm(REG_T1);
#ifdef 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
register uint32 RC asm(REG_T2);
// Semantic action templates
#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 powerpc_cr_register & cr() { return CPU->cr(); }
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_OP
#define DEFINE_OP(CRF, REG) \
void OPPROTO op_load_##REG##_cr##CRF(void) \
{ \
T0 = powerpc_dyngen_helper::cr().get(CRF); \
} \
void OPPROTO op_store_##REG##_cr##CRF(void) \
{ \
powerpc_dyngen_helper::cr().set(CRF, REG); \
#define DEFINE_OP(CRF, REG) \
void OPPROTO op_load_##REG##_cr##CRF(void) \
{ \
REG = powerpc_dyngen_helper::cr().get(CRF); \
} \
void OPPROTO op_store_##REG##_cr##CRF(void) \
{ \
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(1, T0);
DEFINE_OP(2, T0);
DEFINE_OP(3, T0);
DEFINE_OP(4, T0);
DEFINE_OP(5, T0);
DEFINE_OP(6, T0);
DEFINE_OP(7, T0);
DEFINE_OP(0, RC);
DEFINE_OP(1, RC);
DEFINE_OP(2, RC);
DEFINE_OP(3, RC);
DEFINE_OP(4, RC);
DEFINE_OP(5, RC);
DEFINE_OP(6, RC);
DEFINE_OP(7, RC);
#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
@ -394,9 +347,9 @@ static inline void do_execute_branch(uint32 tpc, uint32 npc)
}
template< int crb >
struct CR_comparator {
struct RC_comparator {
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<false, CR_comparator<8> > bnlt_condition;
typedef bool_condition< true, CR_comparator<4> > bgt_condition;
typedef bool_condition<false, CR_comparator<4> > bngt_condition;
typedef bool_condition< true, CR_comparator<2> > beq_condition;
typedef bool_condition<false, CR_comparator<2> > bneq_condition;
typedef bool_condition< true, CR_comparator<1> > bso_condition;
typedef bool_condition<false, CR_comparator<1> > bnso_condition;
typedef bool_condition< true, RC_comparator<8> > blt_condition;
typedef bool_condition<false, RC_comparator<8> > bnlt_condition;
typedef bool_condition< true, RC_comparator<4> > bgt_condition;
typedef bool_condition<false, RC_comparator<4> > bngt_condition;
typedef bool_condition< true, RC_comparator<2> > beq_condition;
typedef bool_condition<false, RC_comparator<2> > bneq_condition;
typedef bool_condition< true, RC_comparator<1> > bso_condition;
typedef bool_condition<false, RC_comparator<1> > bnso_condition;
struct ctr_0x_condition {
static inline bool test() {
@ -453,7 +406,7 @@ void OPPROTO op_##COND##_##CTR(void) \
#define DEFINE_OP(COND) \
DEFINE_OP_CTR(COND,0x); \
DEFINE_OP_CTR(COND,10); \
DEFINE_OP_CTR(COND,11)
DEFINE_OP_CTR(COND,11);
DEFINE_OP(blt);
DEFINE_OP(bgt);
@ -478,52 +431,9 @@ void OPPROTO op_record_nego_T0(void)
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 DEFINE_OP(LHS, RHS) \
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__)
#if DYNGEN_ASM_OPTS && defined(__powerpc__) && 0
#define DEFINE_OP(NAME, COMP, LHS, RHST, RHS) \
void OPPROTO op_##NAME##_##LHS##_##RHS(void) \
@ -543,26 +453,25 @@ DEFINE_OP(do_compare_logical,"cmplwi",T0,"i",0);
#else
#define DEFINE_OP(NAME, TYPE, LHS, RHS) \
void OPPROTO op_##NAME##_##LHS##_##RHS(void) \
{ \
uint32 cr = powerpc_dyngen_helper::xer().get_so(); \
if ((TYPE)LHS < (TYPE)RHS) \
cr |= standalone_CR_LT_field::mask(); \
else if ((TYPE)LHS > (TYPE)RHS) \
cr |= standalone_CR_GT_field::mask(); \
else \
cr |= standalone_CR_EQ_field::mask(); \
T0 = cr; \
dyngen_barrier(); \
#define DEFINE_OP(NAME, TYPE, LHS, RHS) \
void OPPROTO op_##NAME##_##LHS##_##RHS(void) \
{ \
RC = powerpc_dyngen_helper::xer().get_so(); \
if ((TYPE)LHS < (TYPE)RHS) \
RC |= standalone_CR_LT_field::mask(); \
else if ((TYPE)LHS > (TYPE)RHS) \
RC |= standalone_CR_GT_field::mask(); \
else \
RC |= standalone_CR_EQ_field::mask(); \
dyngen_barrier(); \
}
DEFINE_OP(do_compare,int32,T0,T1);
DEFINE_OP(do_compare,int32,T0,im);
DEFINE_OP(do_compare,int32,T0,0);
DEFINE_OP(do_compare_logical,uint32,T0,T1);
DEFINE_OP(do_compare_logical,uint32,T0,im);
DEFINE_OP(do_compare_logical,uint32,T0,0);
DEFINE_OP(compare,int32,T0,T1);
DEFINE_OP(compare,int32,T0,im);
DEFINE_OP(compare,int32,T0,0);
DEFINE_OP(compare_logical,uint32,T0,T1);
DEFINE_OP(compare_logical,uint32,T0,im);
DEFINE_OP(compare_logical,uint32,T0,0);
#endif

View File

@ -31,51 +31,44 @@
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()
{
invalidate_so_cache();
rc_cache.val_status = RC_cache::STATUS_TRASH;
rc_cache.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();
rc_cache.set_val_status(RC_cache::STATUS_TRASH);
rc_cache.set_crf(-1);
}
void powerpc_dyngen::gen_commit_cr()
{
if (rc_cache.val_status != RC_cache::STATUS_TRASH) {
assert(rc_cache.crf != -1);
do_gen_commit_cr();
if (rc_cache.val_status() == RC_cache::STATUS_VALID &&
rc_cache.so_status() == RC_cache::STATUS_VALID) {
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()
{
if (rc_cache.so_status != RC_cache::STATUS_TRASH) {
assert(rc_cache.crf != -1);
do_gen_commit_so();
if (rc_cache.so_status() == RC_cache::STATUS_VALID) {
const int crf = rc_cache.crf();
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))
gen_commit_cr();
gen_op_compare_T0_T1();
rc_cache.cache_field(crf, RC_cache::STATUS_VALID_LOGICAL);
gen_op_compare_logical_T0_T1();
rc_cache.cache_field(crf);
}
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))
gen_commit_cr();
if (value == 0)
gen_op_compare_T0_0();
gen_op_compare_logical_T0_0();
else
gen_op_compare_T0_im(value);
rc_cache.cache_field(crf, RC_cache::STATUS_VALID_LOGICAL);
gen_op_compare_logical_T0_im(value);
rc_cache.cache_field(crf);
}
/**
@ -193,11 +186,10 @@ void powerpc_dyngen::gen_##OP##_##REG##_cr(int crf) \
} \
}
DEFINE_INSN(load, T0);
DEFINE_INSN(store, T0);
DEFINE_INSN(load, RC);
DEFINE_INSN(store, RC);
DEFINE_INSN(commit, so_cache);
DEFINE_INSN(commit, rc_cache);
DEFINE_INSN(commit_logical, rc_cache);
#undef DEFINE_INSN
@ -206,12 +198,20 @@ void powerpc_dyngen::gen_record_cr0_T0(void)
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)
{
gen_commit_cr();
if (BO_CONDITIONAL_BRANCH(bo)) {
enum { lt, gt, eq, so };
gen_load_T0_cr(bi / 4);
gen_prepare_RC(bi);
const int n = ((bi % 4) << 2) | ((bo >> 1) & 3);
#define _(CR,DCTR,CTR0) (((CR) << 2) | ((DCTR) ? 0 : 2) | ((CTR0) ? 1 : 0))
if (BO_BRANCH_IF_TRUE(bo)) {
@ -239,6 +239,7 @@ void powerpc_dyngen::gen_bc_A0(int bo, int bi, uint32 npc)
#undef _
}
else {
gen_commit_cr();
if (BO_DECREMENT_CTR(bo)) {
gen_decrement_ctr_T0();
if (BO_BRANCH_IF_CTR_ZERO(bo))

View File

@ -37,30 +37,33 @@ class powerpc_dyngen
# include "ppc-dyngen-ops.hpp"
#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 {
STATUS_TRASH,
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()
: 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)
{ return val_status != STATUS_TRASH && crf == test_crf; }
bool has_field(int crf) const
{ return m_crf == crf; }
void cache_field(int new_crf, int new_status = STATUS_VALID)
{ val_status = so_status = new_status; crf = new_crf; }
void cache_field(int crf)
{ m_val_status = m_so_status = STATUS_VALID; m_crf = crf; }
};
RC_cache rc_cache;
@ -102,11 +105,8 @@ public:
// Condition registers
private:
void do_gen_commit_so();
void do_gen_commit_cr();
void gen_commit_so_cache_cr(int crf);
void gen_commit_rc_cache_cr(int crf);
void gen_commit_logical_rc_cache_cr(int crf);
public:
void invalidate_so_cache();
void invalidate_cr_cache();
@ -120,8 +120,9 @@ public:
void gen_load_T1_crb(int i);
void gen_store_T0_crb(int i);
void gen_store_T1_crb(int i);
void gen_load_T0_cr(int crf);
void gen_store_T0_cr(int crf);
void gen_load_RC_cr(int crf);
void gen_store_RC_cr(int crf);
void gen_prepare_RC(int bi);
// Special purpose registers
DEFINE_ALIAS(load_T0_PC,0);