Skip to content

Commit

Permalink
Miscellaneous improvements and fixes to shift elaboration (v0.9).
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
martinwhitaker authored and steveicarus committed Mar 14, 2011
1 parent 337eb3f commit 9084c4a
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 40 deletions.
84 changes: 53 additions & 31 deletions elab_expr.cc
Expand Up @@ -509,9 +509,11 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,

if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {

// Special case: The left expression is zero. No matter
// what the shift, the result is going to be zero.
if (lpc->value().is_defined() && lpc->value().is_zero()) {
// Special case: The left expression is zero. If the
// shift value contains no 'x' or 'z' bits, the result
// is going to be zero.
if (lpc->value().is_defined() && lpc->value().is_zero()
&& (rp->expr_type() == IVL_VT_BOOL)) {

if (debug_elaborate)
cerr << get_fileline() << ": debug: "
Expand All @@ -527,6 +529,11 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
// Handle the super-special case that both
// operands are constants. Precalculate the
// entire value here.
if (!rpc->value().is_defined()) {
tmp = make_const_x(use_wid);
tmp->set_line(*this);
return tmp;
}
verinum lpval = lpc->value();
unsigned shift = rpc->value().as_ulong();
verinum result = lpc->value() << shift;
Expand Down Expand Up @@ -566,6 +573,20 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
}

} 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();
use_wid = lp->expr_width();
if (expr_wid > 0)
Expand Down Expand Up @@ -594,6 +615,11 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
// default way.
if (expr_wid >= 0)
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);
}

Expand Down Expand Up @@ -631,9 +657,11 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,

if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {

// Special case: The left expression is zero. No matter
// what the shift, the result is going to be zero.
if (lpc->value().is_defined() && lpc->value().is_zero()) {
// Special case: The left expression is zero. If the
// shift value contains no 'x' or 'z' bits, the result
// is going to be zero.
if (lpc->value().is_defined() && lpc->value().is_zero()
&& (rp->expr_type() == IVL_VT_BOOL)) {

if (debug_elaborate)
cerr << get_fileline() << ": debug: "
Expand All @@ -647,6 +675,20 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
}

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();

// Special case: The shift is the size of the entire
Expand Down Expand Up @@ -692,36 +734,16 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
tmp = pad_to_width(tmp, use_wid, *this);
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.
if (expr_wid > 0)
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->set_line(*this);
return tmp;
Expand Down
22 changes: 13 additions & 9 deletions tgt-vvp/eval_expr.c
Expand Up @@ -1157,8 +1157,9 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t expr, unsigned wid)
case 'l': /* << (left shift) */
lv = draw_eval_expr_wid(le, wid, 0);

/* shifting 0 gets 0. */
if (lv.base == 0)
/* Shifting 0 gets 0, if we can be sure the shift value
contains no 'x' or 'z' bits. */
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
return lv;

if (lv.base < 4) {
Expand Down Expand Up @@ -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);
}

/* shifting 0 gets 0. */
if (lv.base == 0)
/* Shifting 0 gets 0, if we can be sure the shift value
contains no 'x' or 'z' bits. */
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
return lv;

if (lv.base < 4) {
Expand Down Expand Up @@ -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);
}

/* shifting 0 gets 0. */
if (lv.base == 0)
/* Shifting 0 gets 0, if we can be sure the shift value
contains no 'x' or 'z' bits. */
if ((lv.base == 0) && (ivl_expr_value(re) == IVL_VT_BOOL))
return lv;

/* Sign extend any constant begets itself, if this
expression is signed. */
if ((lv.base < 4) && (ivl_expr_signed(expr)))
/* Similarly, sign extending any constant bit begets itself,
if this expression is signed. */
if ((lv.base < 4) && ivl_expr_signed(expr)
&& (ivl_expr_value(re) == IVL_VT_BOOL))
return lv;

if (lv.base < 4) {
Expand Down

0 comments on commit 9084c4a

Please sign in to comment.