Handle multiply with constant zero.
Multiply of any expression with constant 0 will always return zero. We can handle this early, during elaboration, and save a lot of code downstream the trouble. Also, while we are at it, fix up test_width to re-test the left expression width if the right expression width is unsized. This allows for the left expression code to adapt to the unsized-ness of the expression context.
This commit is contained in:
parent
18de6980ff
commit
03fd124d5a
36
elab_expr.cc
36
elab_expr.cc
|
|
@ -115,14 +115,20 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
|
||||||
ivl_variable_type_t&expr_type,
|
ivl_variable_type_t&expr_type,
|
||||||
bool&unsized_flag) const
|
bool&unsized_flag) const
|
||||||
{
|
{
|
||||||
bool flag_left = false;
|
|
||||||
bool flag_right = false;
|
|
||||||
ivl_variable_type_t expr_type_left = IVL_VT_NO_TYPE;
|
ivl_variable_type_t expr_type_left = IVL_VT_NO_TYPE;
|
||||||
ivl_variable_type_t expr_type_right= IVL_VT_NO_TYPE;
|
ivl_variable_type_t expr_type_right= IVL_VT_NO_TYPE;
|
||||||
|
|
||||||
|
bool flag_left = unsized_flag;
|
||||||
unsigned wid_left = left_->test_width(des,scope, min, 0, expr_type_left, flag_left);
|
unsigned wid_left = left_->test_width(des,scope, min, 0, expr_type_left, flag_left);
|
||||||
|
|
||||||
|
bool flag_right = flag_left;
|
||||||
unsigned wid_right = right_->test_width(des,scope, min, 0, expr_type_right, flag_right);
|
unsigned wid_right = right_->test_width(des,scope, min, 0, expr_type_right, flag_right);
|
||||||
|
|
||||||
|
if (flag_right && !flag_left) {
|
||||||
|
flag_left = flag_right;
|
||||||
|
wid_left = left_->test_width(des, scope, min, 0, expr_type_right, flag_right);
|
||||||
|
}
|
||||||
|
|
||||||
if (flag_left || flag_right)
|
if (flag_left || flag_right)
|
||||||
unsized_flag = true;
|
unsized_flag = true;
|
||||||
|
|
||||||
|
|
@ -624,6 +630,32 @@ NetExpr* PEBinary::elaborate_expr_base_mult_(Design*des,
|
||||||
rp = pad_to_width(rp, expr_wid);
|
rp = pad_to_width(rp, expr_wid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep constants on the right side.
|
||||||
|
if (dynamic_cast<NetEConst*>(lp)) {
|
||||||
|
NetExpr*tmp = lp;
|
||||||
|
lp = rp;
|
||||||
|
rp = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle a few special case multiplies against constants.
|
||||||
|
if (NetEConst*rp_const = dynamic_cast<NetEConst*> (rp)) {
|
||||||
|
verinum rp_val = rp_const->value();
|
||||||
|
|
||||||
|
int use_wid = expr_wid;
|
||||||
|
if (use_wid < 0)
|
||||||
|
use_wid = max(rp->expr_width(), lp->expr_width());
|
||||||
|
|
||||||
|
if (! rp_val.is_defined()) {
|
||||||
|
NetEConst*tmp = make_const_x(use_wid);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rp_val.is_zero()) {
|
||||||
|
NetEConst*tmp = make_const_0(use_wid);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Multiply will guess a width that is the sum of the
|
// Multiply will guess a width that is the sum of the
|
||||||
// widths of the operand. If that sum is too small, then
|
// widths of the operand. If that sum is too small, then
|
||||||
// pad one of the arguments enough that the sum is the
|
// pad one of the arguments enough that the sum is the
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue