Account for unsized arguments to comparisons.

Comparison expressions have sorta-self-determined arguments.
Handle the special cause that some of the arguments may be
themselves unsized, and so expecting to be even wider then
otherwise.
This commit is contained in:
Stephen Williams 2010-04-27 11:55:59 -07:00
parent 46a22e9ea2
commit c4098cffdf
3 changed files with 63 additions and 38 deletions

View File

@ -92,6 +92,8 @@ bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
PEBComp::PEBComp(char op, PExpr*l, PExpr*r) PEBComp::PEBComp(char op, PExpr*l, PExpr*r)
: PEBinary(op, l, r) : PEBinary(op, l, r)
{ {
left_width_ = 0;
right_width_ = 0;
} }
PEBComp::~PEBComp() PEBComp::~PEBComp()

View File

@ -540,6 +540,10 @@ class PEBComp : public PEBinary {
NetExpr* elaborate_expr(Design*des, NetScope*scope, NetExpr* elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const; int expr_width, bool sys_task_arg) const;
NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
private:
int left_width_;
int right_width_;
}; };
/* /*

View File

@ -829,13 +829,61 @@ NetExpr* PEBinary::elaborate_expr_base_add_(Design*des,
return tmp; return tmp;
} }
unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, unsigned PEBComp::test_width(Design*des, NetScope*scope, unsigned, unsigned,
ivl_variable_type_t&expr_type__, ivl_variable_type_t&my_expr_type,
bool&) bool&)
{ {
// The width and type of a comparison operator is fixed and
// well known. Set them now.
expr_type_ = IVL_VT_LOGIC; expr_type_ = IVL_VT_LOGIC;
expr_type__ = expr_type_; my_expr_type = expr_type_;
expr_width_ = 1; expr_width_ = 1;
// The widths of operands are self-determined, but need to be
// figured out.
bool unsized_flag = false;
ivl_variable_type_t left_type = IVL_VT_NO_TYPE;
unsigned left_width = left_->test_width(des, scope, 0, 0, left_type, unsized_flag);
bool left_unsized_flag = unsized_flag;
ivl_variable_type_t right_type = IVL_VT_NO_TYPE;
unsigned right_width = right_->test_width(des, scope, 0, 0, right_type, unsized_flag);
if (left_unsized_flag != unsized_flag) {
left_width = left_->test_width(des, scope, 0, 0, left_type, unsized_flag);
}
int try_wid_l = left_width;
if (type_is_vectorable(left_type) && (right_width > left_width))
try_wid_l = right_width;
int try_wid_r = right_width;
if (type_is_vectorable(right_type) && (left_width > right_width))
try_wid_r = left_width;
// If the expression is unsized and smaller then the integer
// minimum, then tweak the size up.
// NOTE: I really would rather try to figure out what it would
// take to get expand the sub-expressions so that they are
// exactly the right width to behave just like infinite
// width. I suspect that adding 1 more is sufficient in all
// cases, but I'm not certain. Ideas?
if (type_is_vectorable(left_type) && unsized_flag && try_wid_l<(int)integer_width)
try_wid_l += 1;
if (type_is_vectorable(right_type) && unsized_flag && try_wid_r<(int)integer_width)
try_wid_r += 1;
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Comparison expression operands are "
<< left_width << " bits and "
<< right_width << " bits. Resorting to "
<< try_wid_l << " bits and "
<< try_wid_r << " bits." << endl;
}
left_width_ = try_wid_l;
right_width_ = try_wid_r;
return 1; return 1;
} }
@ -845,37 +893,8 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
assert(left_); assert(left_);
assert(right_); assert(right_);
bool unsized_flag = false; NetExpr*lp = left_->elaborate_expr(des, scope, left_width_, false);
ivl_variable_type_t left_type = IVL_VT_NO_TYPE; NetExpr*rp = right_->elaborate_expr(des, scope, right_width_, false);
unsigned left_width = left_->test_width(des, scope, 0, 0, left_type, unsized_flag);
bool save_flag = unsized_flag;
ivl_variable_type_t right_type = IVL_VT_NO_TYPE;
unsigned right_width = right_->test_width(des, scope, 0, 0, right_type, unsized_flag);
if (save_flag != unsized_flag)
left_width = left_->test_width(des, scope, 0, 0, left_type, unsized_flag);
/* Width of operands is self-determined. */
int use_wid_l = left_width;
if (type_is_vectorable(left_type) && (right_width > left_width))
use_wid_l = right_width;
int use_wid_r = right_width;
if (type_is_vectorable(right_type) && (left_width > right_width))
use_wid_r = left_width;
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Comparison expression operands are "
<< left_width << " bits and "
<< right_width << " bits. Resorting to "
<< use_wid_l << " bits and "
<< use_wid_r << " bits." << endl;
}
NetExpr*lp = left_->elaborate_expr(des, scope, use_wid_l, false);
NetExpr*rp = right_->elaborate_expr(des, scope, use_wid_r, false);
if ((lp == 0) || (rp == 0)) { if ((lp == 0) || (rp == 0)) {
delete lp; delete lp;
delete rp; delete rp;
@ -888,12 +907,12 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
// pad the width here. This matters because if the arguments // pad the width here. This matters because if the arguments
// are signed, then this padding will do sign extension. // are signed, then this padding will do sign extension.
if (type_is_vectorable(lp->expr_type())) if (type_is_vectorable(lp->expr_type()))
lp = pad_to_width(lp, use_wid_l, *this); lp = pad_to_width(lp, left_width_, *this);
if (type_is_vectorable(rp->expr_type())) if (type_is_vectorable(rp->expr_type()))
rp = pad_to_width(rp, use_wid_r, *this); rp = pad_to_width(rp, right_width_, *this);
eval_expr(lp, use_wid_l); eval_expr(lp, left_width_);
eval_expr(rp, use_wid_r); eval_expr(rp, right_width_);
// Handle some operand-specific special cases... // Handle some operand-specific special cases...
switch (op_) { switch (op_) {