More robust use of precalculated expressions, and

Separate lookaside for written variables that can
 also be reused.
This commit is contained in:
steve 2005-09-17 01:01:00 +00:00
parent 7235706923
commit 672aa61ae7
4 changed files with 171 additions and 57 deletions

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval_expr.c,v 1.121 2005/09/15 02:49:47 steve Exp $"
#ident "$Id: eval_expr.c,v 1.122 2005/09/17 01:01:00 steve Exp $"
#endif
# include "vvp_priv.h"
@ -274,8 +274,8 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t exp,
if (ivl_expr_width(re) > wid)
wid = ivl_expr_width(re);
lv = draw_eval_expr_wid(le, wid, stuff_ok_flag&STUFF_OK_XZ);
rv = draw_eval_expr_wid(re, wid, stuff_ok_flag&STUFF_OK_XZ);
lv = draw_eval_expr_wid(le, wid, stuff_ok_flag&~STUFF_OK_47);
rv = draw_eval_expr_wid(re, wid, stuff_ok_flag&~STUFF_OK_47);
switch (ivl_expr_opcode(exp)) {
case 'E': /* === */
@ -1057,7 +1057,7 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
return draw_mul_immediate(le, re, wid);
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
rv = draw_eval_expr_wid(re, wid, STUFF_OK_XZ);
rv = draw_eval_expr_wid(re, wid, STUFF_OK_XZ|STUFF_OK_RO);
if (lv.wid != wid) {
fprintf(stderr, "XXXX ivl_expr_opcode(exp) = %c,"
@ -1198,11 +1198,14 @@ static struct vector_info draw_binary_expr(ivl_expr_t exp,
* expression, then copying it into the continguous vector of the
* result. Do this until the result vector is filled.
*/
static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid)
static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid,
int stuff_ok_flag)
{
unsigned off, rep;
struct vector_info res;
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1;
/* Allocate a vector to hold the result. */
res.base = allocate_vector(wid);
res.wid = wid;
@ -1232,7 +1235,7 @@ static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid)
/* Try to locate the subexpression in the
lookaside map. */
avec.base = allocate_vector_exp(arg, awid);
avec.base = allocate_vector_exp(arg, awid, alloc_exclusive);
avec.wid = awid;
trans = awid;
@ -1517,15 +1520,21 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res)
}
}
static struct vector_info draw_signal_expr(ivl_expr_t exp, unsigned wid)
static struct vector_info draw_signal_expr(ivl_expr_t exp, unsigned wid,
int stuff_ok_flag)
{
struct vector_info res;
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1;
/* Already in the vector lookaside? */
res.base = allocate_vector_exp(exp, wid);
res.base = allocate_vector_exp(exp, wid, alloc_exclusive);
res.wid = wid;
if (res.base != 0)
if (res.base != 0) {
fprintf(vvp_out, "; Reuse signal base=%u wid=%u from lookaside.\n",
res.base, res.wid);
return res;
}
res.base = allocate_vector(wid);
res.wid = wid;
@ -1643,16 +1652,19 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
return res;
}
static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid)
static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
int stuff_ok_flag)
{
struct vector_info subv, shiv, res;
ivl_expr_t sube = ivl_expr_oper1(exp);
ivl_expr_t shift = ivl_expr_oper2(exp);
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO)? 0 : 1;
/* First look for the self expression in the lookaside, and
allocate that if possible. If I find it, then immediatly
return that. */
if ( (res.base = allocate_vector_exp(exp, wid)) != 0) {
if ( (res.base = allocate_vector_exp(exp, wid, alloc_exclusive)) != 0) {
fprintf(vvp_out, "; Reuse base=%u wid=%u from lookaside.\n",
res.base, wid);
res.wid = wid;
@ -1712,6 +1724,7 @@ static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid)
res.wid = wid;
subv.base += wid;
subv.wid -= wid;
clr_vector(subv);
} else if (subv.wid == wid) {
@ -1742,7 +1755,7 @@ static struct vector_info draw_ternary_expr(ivl_expr_t exp, unsigned wid)
/* Evaluate the condition expression, and if necessary reduce
it to a single bit. */
tst = draw_eval_expr(cond, STUFF_OK_XZ);
tst = draw_eval_expr(cond, STUFF_OK_XZ|STUFF_OK_RO);
if ((tst.base >= 4) && (tst.wid > 1)) {
struct vector_info tmp;
@ -2064,7 +2077,7 @@ struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned wid,
break;
case IVL_EX_CONCAT:
res = draw_concat_expr(exp, wid);
res = draw_concat_expr(exp, wid, stuff_ok_flag);
break;
case IVL_EX_NUMBER:
@ -2079,11 +2092,11 @@ struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned wid,
if (ivl_expr_oper2(exp) == 0)
res = draw_pad_expr(exp, wid);
else
res = draw_select_expr(exp, wid);
res = draw_select_expr(exp, wid, stuff_ok_flag);
break;
case IVL_EX_SIGNAL:
res = draw_signal_expr(exp, wid);
res = draw_signal_expr(exp, wid, stuff_ok_flag);
break;
case IVL_EX_TERNARY:
@ -2117,6 +2130,11 @@ struct vector_info draw_eval_expr(ivl_expr_t exp, int stuff_ok_flag)
/*
* $Log: eval_expr.c,v $
* Revision 1.122 2005/09/17 01:01:00 steve
* More robust use of precalculated expressions, and
* Separate lookaside for written variables that can
* also be reused.
*
* Revision 1.121 2005/09/15 02:49:47 steve
* Better reuse of IVL_EX_SELECT expressions.
*

View File

@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vector.c,v 1.6 2005/09/15 02:50:13 steve Exp $"
#ident "$Id: vector.c,v 1.7 2005/09/17 01:01:00 steve Exp $"
#endif
# include "vvp_priv.h"
@ -31,28 +31,15 @@
static struct allocation_score_s {
ivl_expr_t exp;
unsigned bit;
unsigned alloc : 1;
ivl_signal_t sig;
unsigned exp_bit : 24;
unsigned sig_bit : 24;
unsigned alloc : 8;
} allocation_map[MAX_VEC] = { {0} };
/* This is the largest bit to have lookaside values. */
static unsigned lookaside_top = 0;
static inline int peek_bit(unsigned addr)
{
return allocation_map[addr].alloc;
}
static inline void set_bit(unsigned addr)
{
allocation_map[addr].alloc = 1;
}
static inline void clr_bit(unsigned addr)
{
allocation_map[addr].alloc = 0;
}
static inline ivl_expr_t peek_exp(unsigned addr)
{
return allocation_map[addr].exp;
@ -60,13 +47,19 @@ static inline ivl_expr_t peek_exp(unsigned addr)
static inline unsigned peek_exp_bit(unsigned addr)
{
return allocation_map[addr].bit;
return allocation_map[addr].exp_bit;
}
static inline void set_exp(unsigned addr, ivl_expr_t exp, unsigned ebit)
{
allocation_map[addr].exp = exp;
allocation_map[addr].bit = ebit;
allocation_map[addr].exp_bit = ebit;
}
static inline void set_sig(unsigned addr, ivl_signal_t exp, unsigned ebit)
{
allocation_map[addr].sig = exp;
allocation_map[addr].sig_bit = ebit;
}
/*
@ -84,8 +77,10 @@ void clr_vector(struct vector_info vec)
if (vec.base < 4)
return;
assert(vec.base >= 8);
for (idx = 0 ; idx < vec.wid ; idx += 1)
clr_bit(vec.base + idx);
for (idx = 0 ; idx < vec.wid ; idx += 1) {
assert( allocation_map[vec.base+idx].alloc > 0);
allocation_map[vec.base+idx].alloc -= 1;
}
}
static unsigned allocate_vector_no_lookaside(unsigned wid, int skip_lookaside)
@ -95,7 +90,8 @@ static unsigned allocate_vector_no_lookaside(unsigned wid, int skip_lookaside)
while (idx < wid) {
assert((base + idx) < MAX_VEC);
if (peek_bit(base+idx) || (skip_lookaside && peek_exp(base+idx))) {
if ((allocation_map[base+idx].alloc > 0)
|| (skip_lookaside && peek_exp(base+idx))) {
base = base + idx + 1;
idx = 0;
@ -105,7 +101,7 @@ static unsigned allocate_vector_no_lookaside(unsigned wid, int skip_lookaside)
}
for (idx = 0 ; idx < wid ; idx += 1) {
set_bit(base+idx);
allocation_map[base+idx].alloc += 1;
set_exp(base+idx, 0, 0);
}
@ -140,21 +136,45 @@ unsigned allocate_vector(unsigned wid)
void clear_expression_lookaside(void)
{
unsigned idx;
for (idx = 0 ; idx < lookaside_top ; idx += 1)
for (idx = 0 ; idx < lookaside_top ; idx += 1) {
set_exp(idx, 0, 0);
set_sig(idx, 0, 0);
}
lookaside_top = 0;
}
void save_expression_lookaside(unsigned addr, ivl_expr_t exp,
unsigned wid)
void save_expression_lookaside(unsigned addr, ivl_expr_t exp, unsigned wid)
{
unsigned idx;
assert(addr >= 8);
assert((addr+wid) <= MAX_VEC);
for (idx = 0 ; idx < wid ; idx += 1)
/* When saving an expression to the lookaside, also clear the
signal saved in the lookaside for these bits. The reason is
that an expression calculation will replace any signal
bits. */
for (idx = 0 ; idx < wid ; idx += 1) {
set_exp(addr+idx, exp, idx);
set_sig(addr+idx, 0, 0);
}
if ((addr+wid) > lookaside_top)
lookaside_top = addr+wid;
}
void save_signal_lookaside(unsigned addr, ivl_signal_t sig, unsigned wid)
{
unsigned idx;
/* Don't bind any of hte low bits to a signal. */
if (addr < 8)
return;
assert((addr+wid) <= MAX_VEC);
for (idx = 0 ; idx < wid ; idx += 1)
set_sig(addr+idx, sig, idx);
if ((addr+wid) > lookaside_top)
lookaside_top = addr+wid;
@ -213,26 +233,56 @@ static int compare_exp(ivl_expr_t l, ivl_expr_t r)
return 0;
}
static unsigned find_expression_lookaside(ivl_expr_t exp,
unsigned wid)
static unsigned find_expression_lookaside(ivl_expr_t exp, unsigned wid)
{
unsigned top;
unsigned idx, match;
ivl_signal_t sig;
if (lookaside_top <= wid)
return 0;
top = lookaside_top - wid + 1;
/* Look in the expression lookaside for this expression. */
assert(exp);
match = 0;
for (idx = 8 ; idx < top ; idx += 1) {
for (idx = 8 ; idx < lookaside_top ; idx += 1) {
if (! compare_exp(allocation_map[idx].exp, exp)) {
match = 0;
continue;
}
if (allocation_map[idx].bit != match) {
if (allocation_map[idx].exp_bit != match) {
match = 0;
continue;
}
match += 1;
if (match == wid)
return idx-match+1;
}
if (ivl_expr_type(exp) != IVL_EX_SIGNAL)
return 0;
sig = ivl_expr_signal(exp);
/* Only reg signals (variables) will be in the signal
lookaside, because only blocking assigned values are in the
signal lookaside. */
if (ivl_signal_type(sig) != IVL_SIT_REG)
return 0;
/* Now look for signal value matches in the signal lookaside. */
match = 0;
for (idx = 8 ; idx < lookaside_top ; idx += 1) {
if (sig != allocation_map[idx].sig) {
match = 0;
continue;
}
if (allocation_map[idx].sig_bit != match) {
match = 0;
continue;
}
@ -251,23 +301,31 @@ static unsigned find_expression_lookaside(ivl_expr_t exp,
* caller will not need to evaluate the expression. If this function
* returns 0, then the expression is not found and nothing is allocated.
*/
unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid)
unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid,
int exclusive_flag)
{
unsigned idx;
unsigned la = find_expression_lookaside(exp, wid);
if (exclusive_flag) {
for (idx = 0 ; idx < wid ; idx += 1)
if (allocation_map[la+idx].alloc)
return 0;
}
for (idx = 0 ; idx < wid ; idx += 1)
allocation_map[la+idx].alloc = 1;
allocation_map[la+idx].alloc += 1;
return la;
}
/*
* $Log: vector.c,v $
* Revision 1.7 2005/09/17 01:01:00 steve
* More robust use of precalculated expressions, and
* Separate lookaside for written variables that can
* also be reused.
*
* Revision 1.6 2005/09/15 02:50:13 steve
* Preserve precalculated expressions when possible.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vvp_priv.h,v 1.35 2005/09/15 02:50:13 steve Exp $"
#ident "$Id: vvp_priv.h,v 1.36 2005/09/17 01:01:00 steve Exp $"
#endif
# include "vvp_config.h"
@ -117,6 +117,12 @@ extern void draw_input_from_net(ivl_nexus_t nex);
*
* STUFF_OK_47 -- This bit is set if the node is allowed to leave a
* result in any of the 4-7 vthread bits.
*
* STUFF_OK_RO -- This bit is set if the node is allowed to nest its
* allocation from vector. It is only true if the client is not
* planning to use this vector as an output. This matters only
* if the expression might be found in the lookaside table, and
* therefore might be multiply allocated if allowed.
*/
struct vector_info {
unsigned base;
@ -128,6 +134,7 @@ extern struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned w,
int stuff_ok_flag);
#define STUFF_OK_XZ 0x0001
#define STUFF_OK_47 0x0002
#define STUFF_OK_RO 0x0004
/*
* This function draws code to evaluate the index expression exp for
@ -164,10 +171,25 @@ extern void draw_memory_index_expr(ivl_memory_t mem, ivl_expr_t exp);
* bits. This remains until the lookaside is cleared. This does not
* clear the allocation, it is still necessary to call clr_vector.
*
* save_signal_lookaside
* Mark the given signal as available in the given register bits.
* This is different from a given expression, in that the signal
* lookaside is in addition to the expression lookaside. The signal
* lookaside is specifically to save on unnecessary loads of a
* signal recently written.
*
* allocate_vector_exp
* This function attempts to locate the expression in the
* lookaside. If it finds it, return a reallocated base for the
* expression. Otherwise, return 0.
*
* The allocate_vector and allocate_vector_exp calls must have
* matching call to clr_vector. Although the allocate_vector will
* never reallocate a vector already allocated, the allocate_vector_exp
* might, so it is possible for allocations to nest in that
* manner. The exclusive_flag to allocate_vector_exp will prevent
* nested allocations. This is needed where the expression result is
* expected to be overwritten.
*/
extern unsigned allocate_vector(unsigned wid);
extern void clr_vector(struct vector_info vec);
@ -176,8 +198,12 @@ extern void clear_expression_lookaside(void);
extern void save_expression_lookaside(unsigned addr,
ivl_expr_t exp,
unsigned wid);
extern void save_signal_lookaside(unsigned addr,
ivl_signal_t sig,
unsigned wid);
extern unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid);
extern unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid,
int exclusive_flag);
extern int number_is_unknown(ivl_expr_t ex);
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid);
@ -213,6 +239,11 @@ extern unsigned thread_count;
/*
* $Log: vvp_priv.h,v $
* Revision 1.36 2005/09/17 01:01:00 steve
* More robust use of precalculated expressions, and
* Separate lookaside for written variables that can
* also be reused.
*
* Revision 1.35 2005/09/15 02:50:13 steve
* Preserve precalculated expressions when possible.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vvp_process.c,v 1.116 2005/09/14 02:53:15 steve Exp $"
#ident "$Id: vvp_process.c,v 1.117 2005/09/17 01:01:00 steve Exp $"
#endif
# include "vvp_priv.h"
@ -104,6 +104,7 @@ static void set_to_lvariable(ivl_lval_t lval,
vvp_signal_label(sig), bit, wid);
} else {
save_signal_lookaside(bit, sig, wid);
fprintf(vvp_out, " %%set/v V_%s, %u, %u;\n",
vvp_signal_label(sig), bit, wid);
@ -577,7 +578,7 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
/* Oh well, do this case the hard way. */
cvec = draw_eval_expr_wid(cex, cond.wid, 0);
cvec = draw_eval_expr_wid(cex, cond.wid, STUFF_OK_RO);
assert(cvec.wid == cond.wid);
switch (ivl_statement_type(net)) {
@ -840,7 +841,8 @@ static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope)
int rc = 0;
unsigned lab_false, lab_out;
ivl_expr_t exp = ivl_stmt_cond_expr(net);
struct vector_info cond = draw_eval_expr(exp, STUFF_OK_XZ|STUFF_OK_47);
struct vector_info cond
= draw_eval_expr(exp, STUFF_OK_XZ|STUFF_OK_47|STUFF_OK_RO);
assert(cond.wid == 1);
@ -1464,6 +1466,11 @@ int draw_func_definition(ivl_scope_t scope)
/*
* $Log: vvp_process.c,v $
* Revision 1.117 2005/09/17 01:01:00 steve
* More robust use of precalculated expressions, and
* Separate lookaside for written variables that can
* also be reused.
*
* Revision 1.116 2005/09/14 02:53:15 steve
* Support bool expressions and compares handle them optimally.
*