Wrap up vecc4 support for left/right shift expressions.

This commit is contained in:
Stephen Williams 2014-01-13 16:11:47 -08:00
parent 6a93b6a7e4
commit b0a9430e98
4 changed files with 45 additions and 325 deletions

View File

@ -1294,152 +1294,6 @@ static struct vector_info draw_binary_expr_logic(ivl_expr_t expr,
return lv;
}
/*
* Draw code to evaluate the << expression. Use the %shiftl/i0
* or %shiftr/i0 instruction to do the real work of shifting. This
* means that I can handle both left and right shifts in this
* function, with the only difference the opcode I generate at the
* end.
*/
static struct vector_info draw_binary_expr_lrs(ivl_expr_t expr, unsigned wid)
{
ivl_expr_t le = ivl_expr_oper1(expr);
ivl_expr_t re = ivl_expr_oper2(expr);
const char*opcode = "?";
struct vector_info lv;
/* Evaluate the expression that is to be shifted. */
switch (ivl_expr_opcode(expr)) {
case 'l': /* << (left shift) */
lv = draw_eval_expr_wid(le, wid, 0);
/* Shifting 0 gets 0, if we can be sure the shift value
contains no 'x' or 'z' bits. */
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
return lv;
if (lv.base < 4) {
struct vector_info tmp;
tmp.base = allocate_vector(lv.wid);
tmp.wid = lv.wid;
if (tmp.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of left shift (<<).\n",
ivl_expr_file(expr), ivl_expr_lineno(expr),
wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, lv.base, lv.wid);
lv = tmp;
}
opcode = "%shiftl";
break;
case 'r': /* >> (unsigned right shift) */
/* with the right shift, there may be high bits that are
shifted into the desired width of the expression, so
we let the expression size itself, if it is bigger
then what is requested of us. */
if (wid > ivl_expr_width(le)) {
lv = draw_eval_expr_wid(le, wid, 0);
} else {
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
}
/* Shifting 0 gets 0, if we can be sure the shift value
contains no 'x' or 'z' bits. */
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
return lv;
if (lv.base < 4) {
struct vector_info tmp;
tmp.base = allocate_vector(lv.wid);
tmp.wid = lv.wid;
if (tmp.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of right shift (>>).\n",
ivl_expr_file(expr), ivl_expr_lineno(expr),
lv.wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, lv.base, lv.wid);
lv = tmp;
}
opcode = "%shiftr";
break;
case 'R': /* >>> (signed right shift) */
/* with the right shift, there may be high bits that are
shifted into the desired width of the expression, so
we let the expression size itself, if it is bigger
then what is requested of us. */
if (wid > ivl_expr_width(le)) {
lv = draw_eval_expr_wid(le, wid, 0);
} else {
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
}
/* Shifting 0 gets 0, if we can be sure the shift value
contains no 'x' or 'z' bits. */
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
return lv;
/* Similarly, sign extending any constant bit begets itself,
if this expression is signed. */
if ((lv.base < 4) && ivl_expr_signed(expr)
&& (ivl_expr_value(re) == IVL_VT_BOOL))
return lv;
if (lv.base < 4) {
struct vector_info tmp;
tmp.base = allocate_vector(lv.wid);
tmp.wid = lv.wid;
if (tmp.base == 0) {
fprintf(stderr, "%s:%u: vvp.tgt error: "
"Unable to allocate %u thread bits "
"for result of right shift (>>>).\n",
ivl_expr_file(expr), ivl_expr_lineno(expr),
lv.wid);
vvp_errors += 1;
}
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
tmp.base, lv.base, lv.wid);
lv = tmp;
}
if (ivl_expr_signed(expr))
opcode = "%shiftr/s";
else
opcode = "%shiftr";
break;
default:
assert(0);
}
/* Figure out the shift amount and load that into the index
register. The value may be a constant, or may need to be
evaluated at run time. */
eval_logic_into_integer(re,0);
fprintf(vvp_out, " %s/i0 %u, %u;\n", opcode, lv.base, lv.wid);
if (lv.base >= 8)
save_expression_lookaside(lv.base, expr, lv.wid);
return lv;
}
static struct vector_info draw_load_add_immediate(ivl_expr_t le,
ivl_expr_t re,
@ -1781,12 +1635,6 @@ static struct vector_info draw_binary_expr(ivl_expr_t expr,
rv = draw_binary_expr_arith(expr, wid);
break;
case 'l': /* << */
case 'r': /* >> */
case 'R': /* >>> */
rv = draw_binary_expr_lrs(expr, wid);
break;
case 'o': /* || (logical or) */
rv = draw_binary_expr_lor(expr, wid, stuff_ok_flag);
stuff_ok_used_flag = 1;
@ -1802,7 +1650,7 @@ static struct vector_info draw_binary_expr(ivl_expr_t expr,
break;
default:
fprintf(stderr, "vvp.tgt error: unsupported binary (%c)\n",
fprintf(stderr, "vvp.tgt error: draw_binary_expr: unsupported binary (%c)\n",
ivl_expr_opcode(expr));
assert(0);
}

View File

@ -336,7 +336,10 @@ static void draw_binary_vec4_lrs(ivl_expr_t expr, int stuff_ok_flag)
fprintf(vvp_out, " %%shiftr %u;\n", use_index_reg);
break;
case 'R': /* >>> */
fprintf(vvp_out, " %%shiftrs %u;\n", use_index_reg);
if (ivl_expr_signed(le))
fprintf(vvp_out, " %%shiftr/s %u;\n", use_index_reg);
else
fprintf(vvp_out, " %%shiftr %u;\n", use_index_reg);
break;
default:
assert(0);

View File

@ -1168,29 +1168,6 @@ The index may be signed, and if less than 0, the beginning bits are
not assigned. Also, if the bits go beyond the end of the signal, those
bits are not written anywhere.
* %shiftl/i0 <bit>, <wid> (XXXX Old implementation)
This instruction shifts the vector left (towards more significant
bits) by the amount in index register 0. The <bit> is the address of
the LSB of the vector, and <wid> the width of the vector. The shift is
done in place. Zero values are shifted in.
For a negative shift the value is padded with 'bx.
* %shiftr/i0 <bit>, <wid> (XXXX Old implementation)
* %shiftr/s/i0 <bit>, <wid> (XXXX Old implementation)
This instruction shifts the vector right (towards the less significant
bits) by the amount in the index register 0. The <bit> is the address
of the LSB of the vector, and <wid> is the width of the vector. The
shift is done in place.
%shiftr/i0 is an unsigned down shift, so zeros are shifted into the
top bits. %shiftr/s/i0 is a signed shift, so the value is sign-extended.
For a negative shift %shiftr/i0 will pad the value with 'bx.
* %shiftl <idx>
* %shiftr <idx>
* %shiftr/s <idx>
@ -1199,6 +1176,12 @@ These instructions shift the top value in the vec4 stack left (towards
MSB) or right, possibly signed. The <idx> is the address of the index
register that contains the amount to shift.
The instruction also checks flag bit 4. If it is true, the result is
replaced with X instead of a shifted result. This is intended to
detect that the index contents were not valid.
For a negative shift, %shiftr will pad the vlaue with 'bx.
* %split/vec4 <wid>
Pull the top vec4 vector from the stack and split it into two

View File

@ -5491,54 +5491,6 @@ bool of_SET_X0(vthread_t thr, vvp_code_t cp)
return true;
}
#if 0
bool of_SHIFTL_I0(vthread_t thr, vvp_code_t cp)
{
int base = cp->bit_idx[0];
int wid = cp->number;
int shift = thr->words[0].w_int;
assert(base >= 4);
thr_check_addr(thr, base+wid-1);
if (thr_get_bit(thr, 4) == BIT4_1) {
// The result is 'bx if the shift amount is undefined.
vvp_vector4_t tmp (wid, BIT4_X);
thr->bits4.set_vec(base, tmp);
} else if (shift >= wid) {
// Shift is so far that all value is shifted out. Write
// in a constant 0 result.
vvp_vector4_t tmp (wid, BIT4_0);
thr->bits4.set_vec(base, tmp);
} else if (shift > 0) {
vvp_vector4_t tmp (thr->bits4, base, wid-shift);
thr->bits4.set_vec(base+shift, tmp);
// Fill zeros on the bottom
vvp_vector4_t fil (shift, BIT4_0);
thr->bits4.set_vec(base, fil);
} else if (shift <= -wid) {
vvp_vector4_t tmp (wid, BIT4_X);
thr->bits4.set_vec(base, tmp);
} else if (shift < 0) {
// For a negative shift we pad with 'bx.
int idx;
for (idx = 0 ; (idx-shift) < wid ; idx += 1) {
unsigned src = base + idx - shift;
unsigned dst = base + idx;
thr_put_bit(thr, dst, thr_get_bit(thr, src));
}
for ( ; idx < wid ; idx += 1)
thr_put_bit(thr, base+idx, BIT4_X);
}
return true;
}
#endif
/*
* %shiftl <idx>
*/
@ -5581,61 +5533,6 @@ bool of_SHIFTL(vthread_t thr, vvp_code_t cp)
return true;
}
#if 0
/*
* This is an unsigned right shift:
*
* %shiftr/i0 <bit>, <wid>
*
* The vector at address <bit> with width <wid> is shifted right a
* number of bits stored in index/word register 0.
*/
bool of_SHIFTR_I0(vthread_t thr, vvp_code_t cp)
{
int base = cp->bit_idx[0];
int wid = cp->number;
int shift = thr->words[0].w_int;
assert(base >= 4);
thr_check_addr(thr, base+wid-1);
if (thr_get_bit(thr, 4) == BIT4_1) {
// The result is 'bx if the shift amount is undefined.
vvp_vector4_t tmp (wid, BIT4_X);
thr->bits4.set_vec(base, tmp);
} else if (shift > wid) {
// Shift so far that the entire vector is shifted out.
vvp_vector4_t tmp (wid, BIT4_0);
thr->bits4.set_vec(base, tmp);
} else if (shift > 0) {
// The mov method should handle overlapped source/dest
thr->bits4.mov(base, base+shift, wid-shift);
vvp_vector4_t tmp (shift, BIT4_0);
thr->bits4.set_vec(base+wid-shift, tmp);
} else if (shift < -wid) {
// Negative shift is so far that all the value is shifted out.
// Write in a constant 'bx result.
vvp_vector4_t tmp (wid, BIT4_X);
thr->bits4.set_vec(base, tmp);
} else if (shift < 0) {
// For a negative shift we pad with 'bx.
vvp_vector4_t tmp (thr->bits4, base, wid+shift);
thr->bits4.set_vec(base-shift, tmp);
vvp_vector4_t fil (-shift, BIT4_X);
thr->bits4.set_vec(base, fil);
}
return true;
}
#endif
/*
* %shiftr <idx>
* This is an unsigned right shift. The <idx> is a number that selects
@ -5678,53 +5575,42 @@ bool of_SHIFTR(vthread_t thr, vvp_code_t cp)
return true;
}
#if 0
bool of_SHIFTR_S_I0(vthread_t thr, vvp_code_t cp)
{
int base = cp->bit_idx[0];
int wid = cp->number;
int shift = thr->words[0].w_int;
vvp_bit4_t sign = thr_get_bit(thr, base+wid-1);
if (thr_get_bit(thr, 4) == BIT4_1) {
// The result is 'bx if the shift amount is undefined.
vvp_vector4_t tmp (wid, BIT4_X);
thr->bits4.set_vec(base, tmp);
} else if (shift >= wid) {
for (int idx = 0 ; idx < wid ; idx += 1)
thr_put_bit(thr, base+idx, sign);
} else if (shift > 0) {
for (int idx = 0 ; idx < (wid-shift) ; idx += 1) {
unsigned src = base + idx + shift;
unsigned dst = base + idx;
thr_put_bit(thr, dst, thr_get_bit(thr, src));
}
for (int idx = (wid-shift) ; idx < wid ; idx += 1)
thr_put_bit(thr, base+idx, sign);
} else if (shift < -wid) {
// Negative shift is so far that all the value is
// shifted out. Write in a constant 'bx result.
vvp_vector4_t tmp (wid, BIT4_X);
thr->bits4.set_vec(base, tmp);
} else if (shift < 0) {
// For a negative shift we pad with 'bx.
vvp_vector4_t tmp (thr->bits4, base, wid+shift);
thr->bits4.set_vec(base-shift, tmp);
vvp_vector4_t fil (-shift, BIT4_X);
thr->bits4.set_vec(base, fil);
}
return true;
}
#endif
/*
* %shiftr/s <wid>
*/
bool of_SHIFTR_S(vthread_t thr, vvp_code_t cp)
{
fprintf(stderr, "XXXX of_SHIFTR_S not implemented\n");
int use_index = cp->number;
int shift = thr->words[use_index].w_int;
vvp_vector4_t val = thr->pop_vec4();
int wid = val.size();
vvp_bit4_t sign_bit = val.value(val.size()-1);
if (thr->flags[4] == BIT4_1) {
val = vvp_vector4_t(wid, BIT4_X);
} else if (shift > wid) {
val = vvp_vector4_t(wid, sign_bit);
} else if (shift > 0) {
val.mov(0, shift, wid-shift);
vvp_vector4_t tmp (shift, sign_bit);
val.set_vec(wid-shift, tmp);
} else if (shift < -wid) {
val = vvp_vector4_t(wid, BIT4_X);
} else if (shift < 0) {
int use_shift = -shift;
val.mov(use_shift, 0, wid-use_shift);
vvp_vector4_t tmp(use_shift, BIT4_X);
val.set_vec(0, tmp);
}
thr->push_vec4(val);
return true;
}