Fix bug in eval of <= compare
The compiler attempts to precalculate the results of <= comparisons. Fix a few corner cases where the arguments are signed. Also fix the important test of constant against non-constant where we try to test if the non-constant value can possibly make the test fail.
This commit is contained in:
parent
db25bba0d0
commit
5b17f2039a
|
|
@ -1770,6 +1770,7 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
|
|||
signed expression and extend it one bit to
|
||||
accommodate a possible sign bit. */
|
||||
verinum zero (verinum::V0, val.len()+1, val.has_len());
|
||||
zero.has_sign(val.has_sign());
|
||||
verinum nval = zero - val;
|
||||
|
||||
if (val.has_len())
|
||||
|
|
|
|||
10
eval_tree.cc
10
eval_tree.cc
|
|
@ -447,11 +447,19 @@ NetEConst* NetEBComp::eval_leeq_()
|
|||
cerr << get_fileline() << ": : " << *this << endl;
|
||||
}
|
||||
|
||||
/* Detect the case where the right side is greater that or
|
||||
/* Detect the case where the right side is greater than or
|
||||
equal to the largest value the left side can possibly
|
||||
have. */
|
||||
assert(left_->expr_width() > 0);
|
||||
verinum lv (verinum::V1, left_->expr_width());
|
||||
if (left_->has_sign() && rv.has_sign()) {
|
||||
// If the expression is signed, then the largest
|
||||
// possible value for the left_ needs to have a 0 in the
|
||||
// sign position.
|
||||
lv.set(lv.len()-1, verinum::V0);
|
||||
lv.has_sign(true);
|
||||
}
|
||||
|
||||
if (lv <= rv) {
|
||||
verinum result(verinum::V1, 1);
|
||||
return new NetEConst(result);
|
||||
|
|
|
|||
32
verinum.cc
32
verinum.cc
|
|
@ -616,13 +616,25 @@ verinum::V operator == (const verinum&left, const verinum&right)
|
|||
|
||||
verinum::V operator <= (const verinum&left, const verinum&right)
|
||||
{
|
||||
verinum::V left_pad = verinum::V0;
|
||||
verinum::V right_pad = verinum::V0;
|
||||
if (left.has_sign() && right.has_sign()) {
|
||||
left_pad = left.get(left.len()-1);
|
||||
right_pad = right.get(right.len()-1);
|
||||
|
||||
if (left_pad == verinum::V1 && right_pad == verinum::V0)
|
||||
return verinum::V1;
|
||||
if (left_pad == verinum::V0 && right_pad == verinum::V1)
|
||||
return verinum::V0;
|
||||
}
|
||||
|
||||
unsigned idx;
|
||||
for (idx = left.len() ; idx > right.len() ; idx -= 1) {
|
||||
if (left[idx-1] != verinum::V0) return verinum::V0;
|
||||
if (left[idx-1] != right_pad) return verinum::V0;
|
||||
}
|
||||
|
||||
for (idx = right.len() ; idx > left.len() ; idx -= 1) {
|
||||
if (right[idx-1] != verinum::V0) return verinum::V1;
|
||||
if (right[idx-1] != left_pad) return verinum::V1;
|
||||
}
|
||||
|
||||
idx = right.len();
|
||||
|
|
@ -643,13 +655,25 @@ verinum::V operator <= (const verinum&left, const verinum&right)
|
|||
|
||||
verinum::V operator < (const verinum&left, const verinum&right)
|
||||
{
|
||||
verinum::V left_pad = verinum::V0;
|
||||
verinum::V right_pad = verinum::V0;
|
||||
if (left.has_sign() && right.has_sign()) {
|
||||
left_pad = left.get(left.len()-1);
|
||||
right_pad = right.get(right.len()-1);
|
||||
|
||||
if (left_pad == verinum::V1 && right_pad == verinum::V0)
|
||||
return verinum::V1;
|
||||
if (left_pad == verinum::V0 && right_pad == verinum::V1)
|
||||
return verinum::V0;
|
||||
}
|
||||
|
||||
unsigned idx;
|
||||
for (idx = left.len() ; idx > right.len() ; idx -= 1) {
|
||||
if (left[idx-1] != verinum::V0) return verinum::V0;
|
||||
if (left[idx-1] != right_pad) return verinum::V0;
|
||||
}
|
||||
|
||||
for (idx = right.len() ; idx > left.len() ; idx -= 1) {
|
||||
if (right[idx-1] != verinum::V0) return verinum::V1;
|
||||
if (right[idx-1] != left_pad) return verinum::V1;
|
||||
}
|
||||
|
||||
while (idx > 0) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue