Improve vvp handling of excessively large shift distances.

(cherry picked from commit 351a4e5f5e)
This commit is contained in:
Martin Whitaker 2019-11-16 12:11:49 +00:00
parent b13b608744
commit 21ca8360fe
5 changed files with 43 additions and 22 deletions

View File

@ -885,13 +885,14 @@ void vvp_shiftl::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_vector4_t out (op_a_.size()); vvp_vector4_t out (op_a_.size());
bool overflow_flag;
unsigned long shift; unsigned long shift;
if (! vector4_to_value(op_b_, shift)) { if (! vector4_to_value(op_b_, overflow_flag, shift)) {
ptr.ptr()->send_vec4(x_val_, 0); ptr.ptr()->send_vec4(x_val_, 0);
return; return;
} }
if (shift > out.size()) if (overflow_flag || shift > out.size())
shift = out.size(); shift = out.size();
for (unsigned idx = 0 ; idx < shift ; idx += 1) for (unsigned idx = 0 ; idx < shift ; idx += 1)
@ -919,13 +920,14 @@ void vvp_shiftr::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_vector4_t out (op_a_.size()); vvp_vector4_t out (op_a_.size());
bool overflow_flag;
unsigned long shift; unsigned long shift;
if (! vector4_to_value(op_b_, shift)) { if (! vector4_to_value(op_b_, overflow_flag, shift)) {
ptr.ptr()->send_vec4(x_val_, 0); ptr.ptr()->send_vec4(x_val_, 0);
return; return;
} }
if (shift > out.size()) if (overflow_flag || shift > out.size())
shift = out.size(); shift = out.size();
for (unsigned idx = shift ; idx < out.size() ; idx += 1) for (unsigned idx = shift ; idx < out.size() ; idx += 1)

View File

@ -587,12 +587,13 @@ or z, then the index register gets the value 0. The %ix/vec4/s
instruction is the same, except that it assumes the source vector is instruction is the same, except that it assumes the source vector is
sign extended to fit the index register. sign extended to fit the index register.
The instruction also writes into bit 4 a 1 if any of the bits of the The instruction also writes into flag 4 a 1 if any of the bits of the
input vector are x or z. This is a flag that the 0 value written into input vector are x or z. This is a flag that the 0 value written into
the index register is really the result of calculating from unknown the index register is really the result of calculating from unknown
bits. bits. It writes an X into flag 4 if the vec4 value overflows the index
register.
4: unknown value 4: unknown value or overflow
5: (reserved) 5: (reserved)
6: (reserved) 6: (reserved)
@ -600,8 +601,8 @@ bits.
* %ix/getv/s <idx>, <functor-label> * %ix/getv/s <idx>, <functor-label>
These instructions are like the %ix/vec4 instructions, except that they These instructions are like the %ix/vec4 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
set bit 4 just like %ix/get. flag 4 just like %ix/get (overflow is not currently checked by ix/getv/s).
* %ix/load <idx>, <low>, <high> * %ix/load <idx>, <low>, <high>

View File

@ -3017,8 +3017,9 @@ bool of_IX_GETV(vthread_t thr, vvp_code_t cp)
vvp_vector4_t vec; vvp_vector4_t vec;
sig->vec4_value(vec); sig->vec4_value(vec);
bool overflow_flag;
uint64_t val; uint64_t val;
bool known_flag = vector4_to_value(vec, val); bool known_flag = vector4_to_value(vec, overflow_flag, val);
if (known_flag) if (known_flag)
thr->words[index].w_uint = val; thr->words[index].w_uint = val;
@ -3026,7 +3027,7 @@ bool of_IX_GETV(vthread_t thr, vvp_code_t cp)
thr->words[index].w_uint = 0; thr->words[index].w_uint = 0;
/* Set bit 4 as a flag if the input is unknown. */ /* Set bit 4 as a flag if the input is unknown. */
thr->flags[4] = known_flag ? BIT4_0 : BIT4_1; thr->flags[4] = known_flag ? (overflow_flag ? BIT4_X : BIT4_0) : BIT4_1;
return true; return true;
} }
@ -3082,12 +3083,19 @@ static uint64_t vec4_to_index(vthread_t thr, bool signed_flag)
thr->flags[4] = BIT4_0; thr->flags[4] = BIT4_0;
assert(sizeof(bits[0]) <= sizeof(v)); assert(sizeof(bits[0]) <= sizeof(v));
//assert(val_size <= 8*sizeof(v));
v = 0; v = 0;
for (unsigned idx = 0 ; idx < val_size ; idx += 8*sizeof(bits[0])) { for (unsigned idx = 0 ; idx < val_size ; idx += 8*sizeof(bits[0])) {
uint64_t tmp = bits[idx/8/sizeof(bits[0])]; uint64_t tmp = bits[idx/8/sizeof(bits[0])];
v |= tmp << idx; if (idx < 8*sizeof(v)) {
v |= tmp << idx;
} else {
bool overflow = signed_flag && (v >> 63) ? ~tmp != 0 : tmp != 0;
if (overflow) {
thr->flags[4] = BIT4_X;
break;
}
}
} }
// Set the high bits that are not necessarily filled in by the // Set the high bits that are not necessarily filled in by the
@ -4936,7 +4944,7 @@ bool of_SHIFTL(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
val = vvp_vector4_t(wid, BIT4_X); val = vvp_vector4_t(wid, BIT4_X);
} else if (shift >= wid) { } else if (thr->flags[4] == BIT4_X || shift >= wid) {
// Shift is so big that all value is shifted out. Write // Shift is so big that all value is shifted out. Write
// a constant 0 result. // a constant 0 result.
val = vvp_vector4_t(wid, BIT4_0); val = vvp_vector4_t(wid, BIT4_0);
@ -4968,7 +4976,7 @@ bool of_SHIFTR(vthread_t thr, vvp_code_t cp)
if (thr->flags[4] == BIT4_1) { if (thr->flags[4] == BIT4_1) {
val = vvp_vector4_t(wid, BIT4_X); val = vvp_vector4_t(wid, BIT4_X);
} else if (shift > wid) { } else if (thr->flags[4] == BIT4_X || shift > wid) {
val = vvp_vector4_t(wid, BIT4_0); val = vvp_vector4_t(wid, BIT4_0);
} else if (shift > 0) { } else if (shift > 0) {
@ -4998,7 +5006,7 @@ bool of_SHIFTR_S(vthread_t thr, vvp_code_t cp)
if (thr->flags[4] == BIT4_1) { if (thr->flags[4] == BIT4_1) {
val = vvp_vector4_t(wid, BIT4_X); val = vvp_vector4_t(wid, BIT4_X);
} else if (shift > wid) { } else if (thr->flags[4] == BIT4_X || shift > wid) {
val = vvp_vector4_t(wid, sign_bit); val = vvp_vector4_t(wid, sign_bit);
} else if (shift > 0) { } else if (shift > 0) {

View File

@ -2042,20 +2042,21 @@ template bool vector4_to_value(const vvp_vector4_t&vec, uint32_t&val,
template bool vector4_to_value(const vvp_vector4_t&vec, uint64_t&val, template bool vector4_to_value(const vvp_vector4_t&vec, uint64_t&val,
bool is_signed, bool is_arithmetic); bool is_signed, bool is_arithmetic);
template <class T> bool vector4_to_value(const vvp_vector4_t&vec, T&val) template <class T> bool vector4_to_value(const vvp_vector4_t&vec,
bool&overflow_flag, T&val)
{ {
T res = 0; T res = 0;
T msk = 1; T msk = 1;
overflow_flag = false;
unsigned size = vec.size(); unsigned size = vec.size();
for (unsigned idx = 0 ; idx < size ; idx += 1) { for (unsigned idx = 0 ; idx < size ; idx += 1) {
switch (vec.value(idx)) { switch (vec.value(idx)) {
case BIT4_0: case BIT4_0:
break; break;
case BIT4_1: case BIT4_1:
// On overflow, return the maximum value of type T
if (msk == 0) if (msk == 0)
res = ~msk; overflow_flag = true;
else else
res |= msk; res |= msk;
break; break;
@ -2070,9 +2071,11 @@ template <class T> bool vector4_to_value(const vvp_vector4_t&vec, T&val)
return true; return true;
} }
template bool vector4_to_value(const vvp_vector4_t&vec, unsigned long&val); template bool vector4_to_value(const vvp_vector4_t&vec, bool&overflow_flag,
unsigned long&val);
#ifndef UL_AND_TIME64_SAME #ifndef UL_AND_TIME64_SAME
template bool vector4_to_value(const vvp_vector4_t&vec, vvp_time64_t&val); template bool vector4_to_value(const vvp_vector4_t&vec, bool&overflow_flag,
vvp_time64_t&val);
#endif #endif
bool vector4_to_value(const vvp_vector4_t&vec, double&val, bool signed_flag) bool vector4_to_value(const vvp_vector4_t&vec, double&val, bool signed_flag)

View File

@ -558,7 +558,14 @@ template <class T> extern bool vector4_to_value(const vvp_vector4_t&a, T&val,
bool is_signed, bool is_signed,
bool is_arithmetic =true); bool is_arithmetic =true);
template <class T> extern bool vector4_to_value(const vvp_vector4_t&a, T&val); template <class T> extern bool vector4_to_value(const vvp_vector4_t&a,
bool&overflow_flag, T&val);
template <class T> inline bool vector4_to_value(const vvp_vector4_t&a, T&val)
{
bool overflow_flag;
return vector4_to_value(a, overflow_flag, val);
}
extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed); extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed);