Miscellaneous improvements and fixes to shift elaboration (v0.9).
This patch ensures that the result of a shift is an undefined value if the right operand is an undefined value. It also improves the code generated for right shifts where the right operand is constant (which fixes the compiler crash on pr3098439b in the test suite).
This commit is contained in:
parent
337eb3f8e7
commit
9084c4aab1
84
elab_expr.cc
84
elab_expr.cc
|
|
@ -509,9 +509,11 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
|
||||||
|
|
||||||
if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {
|
if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {
|
||||||
|
|
||||||
// Special case: The left expression is zero. No matter
|
// Special case: The left expression is zero. If the
|
||||||
// what the shift, the result is going to be zero.
|
// shift value contains no 'x' or 'z' bits, the result
|
||||||
if (lpc->value().is_defined() && lpc->value().is_zero()) {
|
// is going to be zero.
|
||||||
|
if (lpc->value().is_defined() && lpc->value().is_zero()
|
||||||
|
&& (rp->expr_type() == IVL_VT_BOOL)) {
|
||||||
|
|
||||||
if (debug_elaborate)
|
if (debug_elaborate)
|
||||||
cerr << get_fileline() << ": debug: "
|
cerr << get_fileline() << ": debug: "
|
||||||
|
|
@ -527,6 +529,11 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
|
||||||
// Handle the super-special case that both
|
// Handle the super-special case that both
|
||||||
// operands are constants. Precalculate the
|
// operands are constants. Precalculate the
|
||||||
// entire value here.
|
// entire value here.
|
||||||
|
if (!rpc->value().is_defined()) {
|
||||||
|
tmp = make_const_x(use_wid);
|
||||||
|
tmp->set_line(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
verinum lpval = lpc->value();
|
verinum lpval = lpc->value();
|
||||||
unsigned shift = rpc->value().as_ulong();
|
unsigned shift = rpc->value().as_ulong();
|
||||||
verinum result = lpc->value() << shift;
|
verinum result = lpc->value() << shift;
|
||||||
|
|
@ -566,6 +573,20 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
|
} else if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
|
||||||
|
// Special case: The shift value contains 'x' or 'z' bits.
|
||||||
|
// Elaborate as a constant-x.
|
||||||
|
if (!rpc->value().is_defined()) {
|
||||||
|
|
||||||
|
if (debug_elaborate)
|
||||||
|
cerr << get_fileline() << ": debug: "
|
||||||
|
<< "Shift by undefined value. "
|
||||||
|
<< "Elaborate as constant 'x'." << endl;
|
||||||
|
|
||||||
|
tmp = make_const_x(expr_wid);
|
||||||
|
tmp->set_line(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
long shift = rpc->value().as_long();
|
long shift = rpc->value().as_long();
|
||||||
use_wid = lp->expr_width();
|
use_wid = lp->expr_width();
|
||||||
if (expr_wid > 0)
|
if (expr_wid > 0)
|
||||||
|
|
@ -594,6 +615,11 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
|
||||||
// default way.
|
// default way.
|
||||||
if (expr_wid >= 0)
|
if (expr_wid >= 0)
|
||||||
lp = pad_to_width(lp, expr_wid, *this);
|
lp = pad_to_width(lp, expr_wid, *this);
|
||||||
|
|
||||||
|
rp = new NetESelect(rp, 0, rp->expr_width());
|
||||||
|
rp->cast_signed(false);
|
||||||
|
rp->set_line(*this);
|
||||||
|
|
||||||
tmp = new NetEBShift(op_, lp, rp);
|
tmp = new NetEBShift(op_, lp, rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -631,9 +657,11 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
|
||||||
|
|
||||||
if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {
|
if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {
|
||||||
|
|
||||||
// Special case: The left expression is zero. No matter
|
// Special case: The left expression is zero. If the
|
||||||
// what the shift, the result is going to be zero.
|
// shift value contains no 'x' or 'z' bits, the result
|
||||||
if (lpc->value().is_defined() && lpc->value().is_zero()) {
|
// is going to be zero.
|
||||||
|
if (lpc->value().is_defined() && lpc->value().is_zero()
|
||||||
|
&& (rp->expr_type() == IVL_VT_BOOL)) {
|
||||||
|
|
||||||
if (debug_elaborate)
|
if (debug_elaborate)
|
||||||
cerr << get_fileline() << ": debug: "
|
cerr << get_fileline() << ": debug: "
|
||||||
|
|
@ -647,6 +675,20 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
|
if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
|
||||||
|
// Special case: The shift value contains 'x' or 'z' bits.
|
||||||
|
// Elaborate as a constant-x.
|
||||||
|
if (!rpc->value().is_defined()) {
|
||||||
|
|
||||||
|
if (debug_elaborate)
|
||||||
|
cerr << get_fileline() << ": debug: "
|
||||||
|
<< "Shift by undefined value. "
|
||||||
|
<< "Elaborate as constant 'x'." << endl;
|
||||||
|
|
||||||
|
tmp = make_const_x(expr_wid);
|
||||||
|
tmp->set_line(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long shift = rpc->value().as_ulong();
|
unsigned long shift = rpc->value().as_ulong();
|
||||||
|
|
||||||
// Special case: The shift is the size of the entire
|
// Special case: The shift is the size of the entire
|
||||||
|
|
@ -692,36 +734,16 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
|
||||||
tmp = pad_to_width(tmp, use_wid, *this);
|
tmp = pad_to_width(tmp, use_wid, *this);
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is lossless, then pad the left expression
|
|
||||||
// enough to cover the right shift.
|
|
||||||
if (expr_wid == -2 && use_wid+shift > lp->expr_width()) {
|
|
||||||
lp->cast_signed(lp->has_sign() && op_=='R');
|
|
||||||
lp = pad_to_width(lp, use_wid + shift, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = new NetEConst(verinum(shift));
|
|
||||||
tmp->set_line(*this);
|
|
||||||
long tmp_wid = lp->expr_width() - shift;
|
|
||||||
if (tmp_wid > use_wid)
|
|
||||||
tmp_wid = use_wid;
|
|
||||||
|
|
||||||
ivl_assert(*this, tmp_wid > 0);
|
|
||||||
ivl_assert(*this, use_wid > 0);
|
|
||||||
|
|
||||||
// Implement the right-shift by part-selecting the low
|
|
||||||
// bits out. Pad the result of the part select back out
|
|
||||||
// to the desired size.
|
|
||||||
tmp = new NetESelect(lp, tmp, tmp_wid);
|
|
||||||
tmp->set_line(*this);
|
|
||||||
tmp->cast_signed(lp->has_sign() && op_=='R');
|
|
||||||
tmp = pad_to_width(tmp, use_wid, *this);
|
|
||||||
return tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback, handle the general case.
|
// Fallback, handle the general case.
|
||||||
if (expr_wid > 0)
|
if (expr_wid > 0)
|
||||||
lp = pad_to_width(lp, expr_wid, *this);
|
lp = pad_to_width(lp, expr_wid, *this);
|
||||||
|
|
||||||
|
rp = new NetESelect(rp, 0, rp->expr_width());
|
||||||
|
rp->cast_signed(false);
|
||||||
|
rp->set_line(*this);
|
||||||
|
|
||||||
tmp = new NetEBShift(op_, lp, rp);
|
tmp = new NetEBShift(op_, lp, rp);
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
return tmp;
|
return tmp;
|
||||||
|
|
|
||||||
|
|
@ -1157,8 +1157,9 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t expr, unsigned wid)
|
||||||
case 'l': /* << (left shift) */
|
case 'l': /* << (left shift) */
|
||||||
lv = draw_eval_expr_wid(le, wid, 0);
|
lv = draw_eval_expr_wid(le, wid, 0);
|
||||||
|
|
||||||
/* shifting 0 gets 0. */
|
/* Shifting 0 gets 0, if we can be sure the shift value
|
||||||
if (lv.base == 0)
|
contains no 'x' or 'z' bits. */
|
||||||
|
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
|
||||||
return lv;
|
return lv;
|
||||||
|
|
||||||
if (lv.base < 4) {
|
if (lv.base < 4) {
|
||||||
|
|
@ -1193,8 +1194,9 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t expr, unsigned wid)
|
||||||
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
|
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shifting 0 gets 0. */
|
/* Shifting 0 gets 0, if we can be sure the shift value
|
||||||
if (lv.base == 0)
|
contains no 'x' or 'z' bits. */
|
||||||
|
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
|
||||||
return lv;
|
return lv;
|
||||||
|
|
||||||
if (lv.base < 4) {
|
if (lv.base < 4) {
|
||||||
|
|
@ -1229,13 +1231,15 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t expr, unsigned wid)
|
||||||
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
|
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shifting 0 gets 0. */
|
/* Shifting 0 gets 0, if we can be sure the shift value
|
||||||
if (lv.base == 0)
|
contains no 'x' or 'z' bits. */
|
||||||
|
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
|
||||||
return lv;
|
return lv;
|
||||||
|
|
||||||
/* Sign extend any constant begets itself, if this
|
/* Similarly, sign extending any constant bit begets itself,
|
||||||
expression is signed. */
|
if this expression is signed. */
|
||||||
if ((lv.base < 4) && (ivl_expr_signed(expr)))
|
if ((lv.base < 4) && ivl_expr_signed(expr)
|
||||||
|
&& (ivl_expr_value(re) == IVL_VT_BOOL))
|
||||||
return lv;
|
return lv;
|
||||||
|
|
||||||
if (lv.base < 4) {
|
if (lv.base < 4) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue