Enhance %shiftr/i0 and $shiftl/i0 to work with negative shifts.

The %shiftr/i0 and %shiftl/i0 opcodes are used for some part
selects and if we have a negative shift we want the value to be
padded with 'bx. This patch enhances the two %shift/i0 opcodes
to work with negative shifts and for negative shifts pad with
'bx instead of 'b0.

It also fixes %ix/get/s to use a uint64_t instead of a unsigned
long to avoid problems with sign extension on 32 bit machines.
This commit is contained in:
Cary R 2009-08-25 09:55:27 -07:00 committed by Stephen Williams
parent d108221fef
commit ecb00017cb
2 changed files with 47 additions and 12 deletions

View File

@ -417,7 +417,7 @@ These instructions are like the %ix/get instructions, except that they
read directly from a functor label instead of from thread bits. They read directly from a functor label instead of from thread bits. They
set bit 4 just like %ix/get. set bit 4 just like %ix/get.
* %ix/load <idx>, <low> <high> * %ix/load <idx>, <low>, <high>
This instruction loads an immediate value into the addressed index This instruction loads an immediate value into the addressed index
register. The index register holds signed 64 bit numeric values, so register. The index register holds signed 64 bit numeric values, so
@ -428,9 +428,9 @@ vector. The values are unsigned decimal values and are combined as
<high> << 32 | <low> to produce the final value. <high> << 32 | <low> to produce the final value.
* %ix/add <idx>, <low> <high> * %ix/add <idx>, <low>, <high>
* %ix/sub <idx>, <low> <high> * %ix/sub <idx>, <low>, <high>
* %ix/mul <idx>, <low> <high> * %ix/mul <idx>, <low>, <high>
These instructions add, subtract, or multiply the selected index These instructions add, subtract, or multiply the selected index
register by the immediate value. The 64 bit immediate value is built register by the immediate value. The 64 bit immediate value is built
@ -758,6 +758,8 @@ 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 the LSB of the vector, and <wid> the width of the vector. The shift is
done in place. Zero values are shifted in. done in place. Zero values are shifted in.
For a negative shift the value is padded with 'bx.
* %shiftr/i0 <bit>, <wid> * %shiftr/i0 <bit>, <wid>
* %shiftr/s/i0 <bit>, <wid> * %shiftr/s/i0 <bit>, <wid>
@ -769,6 +771,8 @@ shift is done in place.
%shiftr/i0 is an unsigned down shift, so zeros are shifted into the %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. 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.
* %sub <bit-l>, <bit-r>, <wid> * %sub <bit-l>, <bit-r>, <wid>
This instruction arithmetically subtracts the right vector out of the This instruction arithmetically subtracts the right vector out of the

View File

@ -2642,7 +2642,7 @@ bool of_IX_GET_S(vthread_t thr, vvp_code_t cp)
unsigned base = cp->bit_idx[1]; unsigned base = cp->bit_idx[1];
unsigned width = cp->number; unsigned width = cp->number;
unsigned long v = 0; uint64_t v = 0;
bool unknown_flag = false; bool unknown_flag = false;
vvp_bit4_t vv = BIT4_0; vvp_bit4_t vv = BIT4_0;
@ -2654,7 +2654,7 @@ bool of_IX_GET_S(vthread_t thr, vvp_code_t cp)
break; break;
} }
v |= (unsigned long) vv << i; v |= (uint64_t) vv << i;
if (base >= 4) if (base >= 4)
base += 1; base += 1;
@ -2662,7 +2662,7 @@ bool of_IX_GET_S(vthread_t thr, vvp_code_t cp)
/* Sign-extend to fill the integer value. */ /* Sign-extend to fill the integer value. */
if (!unknown_flag) { if (!unknown_flag) {
unsigned long pad = vv; uint64_t pad = vv;
for (unsigned i = width ; i < 8*sizeof(v) ; i += 1) { for (unsigned i = width ; i < 8*sizeof(v) ; i += 1) {
v |= pad << i; v |= pad << i;
} }
@ -4206,7 +4206,7 @@ bool of_SHIFTL_I0(vthread_t thr, vvp_code_t cp)
{ {
unsigned base = cp->bit_idx[0]; unsigned base = cp->bit_idx[0];
unsigned wid = cp->number; unsigned wid = cp->number;
unsigned long shift = thr->words[0].w_int; long shift = thr->words[0].w_int;
assert(base >= 4); assert(base >= 4);
thr_check_addr(thr, base+wid-1); thr_check_addr(thr, base+wid-1);
@ -4215,7 +4215,8 @@ bool of_SHIFTL_I0(vthread_t thr, vvp_code_t cp)
// The result is 'bx if the shift amount is undefined. // The result is 'bx if the shift amount is undefined.
vvp_vector4_t tmp (wid, BIT4_X); vvp_vector4_t tmp (wid, BIT4_X);
thr->bits4.set_vec(base, tmp); thr->bits4.set_vec(base, tmp);
} else if (shift >= wid) {
} else if (shift >= (long)wid) {
// Shift is so far that all value is shifted out. Write // Shift is so far that all value is shifted out. Write
// in a constant 0 result. // in a constant 0 result.
vvp_vector4_t tmp (wid, BIT4_0); vvp_vector4_t tmp (wid, BIT4_0);
@ -4228,6 +4229,17 @@ bool of_SHIFTL_I0(vthread_t thr, vvp_code_t cp)
// Fill zeros on the bottom // Fill zeros on the bottom
vvp_vector4_t fil (shift, BIT4_0); vvp_vector4_t fil (shift, BIT4_0);
thr->bits4.set_vec(base, fil); thr->bits4.set_vec(base, fil);
} else if (shift < 0) {
// For a negative shift we pad with 'bx.
unsigned 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; return true;
} }
@ -4244,12 +4256,16 @@ bool of_SHIFTR_I0(vthread_t thr, vvp_code_t cp)
{ {
unsigned base = cp->bit_idx[0]; unsigned base = cp->bit_idx[0];
unsigned wid = cp->number; unsigned wid = cp->number;
unsigned long shift = thr->words[0].w_int; long shift = thr->words[0].w_int;
assert(base >= 4);
thr_check_addr(thr, base+wid-1);
if (thr_get_bit(thr, 4) == BIT4_1) { if (thr_get_bit(thr, 4) == BIT4_1) {
// The result is 'bx if the shift amount is undefined. // The result is 'bx if the shift amount is undefined.
vvp_vector4_t tmp (wid, BIT4_X); vvp_vector4_t tmp (wid, BIT4_X);
thr->bits4.set_vec(base, tmp); thr->bits4.set_vec(base, tmp);
} else if (shift > 0) { } else if (shift > 0) {
unsigned idx; unsigned idx;
for (idx = 0 ; (idx+shift) < wid ; idx += 1) { for (idx = 0 ; (idx+shift) < wid ; idx += 1) {
@ -4259,6 +4275,21 @@ bool of_SHIFTR_I0(vthread_t thr, vvp_code_t cp)
} }
for ( ; idx < wid ; idx += 1) for ( ; idx < wid ; idx += 1)
thr_put_bit(thr, base+idx, BIT4_0); thr_put_bit(thr, base+idx, BIT4_0);
} else if (shift < -(long)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; return true;
} }
@ -4271,7 +4302,7 @@ bool of_SHIFTR_S_I0(vthread_t thr, vvp_code_t cp)
vvp_bit4_t sign = thr_get_bit(thr, base+wid-1); vvp_bit4_t sign = thr_get_bit(thr, base+wid-1);
if (thr_get_bit(thr, 4) == BIT4_1) { if (thr_get_bit(thr, 4) == BIT4_1) {
// The result is 'bx if the shift amount is undefined. // The result is 'bx if the shift amount is undefined.
vvp_vector4_t tmp (wid, BIT4_X); vvp_vector4_t tmp (wid, BIT4_X);
thr->bits4.set_vec(base, tmp); thr->bits4.set_vec(base, tmp);
} else if (shift >= wid) { } else if (shift >= wid) {