Improvements to strict-expr-width mode.
Enable error reporting when an unsized number is used in a concatenation operand. Allow greater pruning of expressions containing unsized numbers.
This commit is contained in:
parent
bb39d09d5e
commit
4625e7e2b6
6
PExpr.cc
6
PExpr.cc
|
|
@ -83,12 +83,14 @@ const char* PExpr::width_mode_name(width_mode_t mode)
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case PExpr::SIZED:
|
case PExpr::SIZED:
|
||||||
return "sized";
|
return "sized";
|
||||||
|
case PExpr::UNSIZED:
|
||||||
|
return "unsized";
|
||||||
case PExpr::EXPAND:
|
case PExpr::EXPAND:
|
||||||
return "expand";
|
return "expand";
|
||||||
case PExpr::LOSSLESS:
|
case PExpr::LOSSLESS:
|
||||||
return "lossless";
|
return "lossless";
|
||||||
case PExpr::UNSIZED:
|
case PExpr::UPSIZE:
|
||||||
return "unsized";
|
return "upsize";
|
||||||
default:
|
default:
|
||||||
return "??";
|
return "??";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
42
PExpr.h
42
PExpr.h
|
|
@ -45,9 +45,10 @@ class PPackage;
|
||||||
class PExpr : public LineInfo {
|
class PExpr : public LineInfo {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum width_mode_t { SIZED, EXPAND, LOSSLESS, UNSIZED };
|
// Mode values used by test_width() (see below for description).
|
||||||
|
enum width_mode_t { SIZED, UNSIZED, EXPAND, LOSSLESS, UPSIZE };
|
||||||
|
|
||||||
// Flag values that can be passed to elaborate_expr.
|
// Flag values that can be passed to elaborate_expr().
|
||||||
static const unsigned NO_FLAGS = 0x0;
|
static const unsigned NO_FLAGS = 0x0;
|
||||||
static const unsigned NEED_CONST = 0x1;
|
static const unsigned NEED_CONST = 0x1;
|
||||||
static const unsigned SYS_TASK_ARG = 0x2;
|
static const unsigned SYS_TASK_ARG = 0x2;
|
||||||
|
|
@ -86,29 +87,38 @@ class PExpr : public LineInfo {
|
||||||
// test the width of an expression. In SIZED mode the expression
|
// test the width of an expression. In SIZED mode the expression
|
||||||
// width will be calculated strictly according to the IEEE standard
|
// width will be calculated strictly according to the IEEE standard
|
||||||
// rules for expression width.
|
// rules for expression width.
|
||||||
// If the expression contains an unsized literal, mode will be
|
//
|
||||||
// changed to LOSSLESS. In LOSSLESS mode the expression width will
|
// If the expression is found to contain an unsized literal number
|
||||||
// be calculated as the minimum width necessary to avoid arithmetic
|
// and gn_strict_expr_width_flag is set, mode will be changed to
|
||||||
|
// UNSIZED. In UNSIZED mode the expression width will be calculated
|
||||||
|
// exactly as in SIZED mode - the change in mode simply flags that
|
||||||
|
// the expression contains an unsized numbers.
|
||||||
|
//
|
||||||
|
// If the expression is found to contain an unsized literal number
|
||||||
|
// and gn_strict_expr_width_flag is not set, mode will be changed
|
||||||
|
// to LOSSLESS. In LOSSLESS mode the expression width will be
|
||||||
|
// calculated as the minimum width necessary to avoid arithmetic
|
||||||
// overflow or underflow.
|
// overflow or underflow.
|
||||||
// If the expression both contains an unsized literal and contains
|
//
|
||||||
|
// Once in LOSSLESS mode, if the expression is found to contain
|
||||||
// an operation that coerces a vector operand to a different type
|
// an operation that coerces a vector operand to a different type
|
||||||
// (signed <-> unsigned), mode is changed to UNSIZED. UNSIZED mode
|
// (signed <-> unsigned), mode will be changed to UPSIZE. UPSIZE
|
||||||
// is the same as LOSSLESS, except that the final expression width
|
// mode is the same as LOSSLESS, except that the final expression
|
||||||
// will be forced to be at least integer_width. This is necessary
|
// width will be forced to be at least integer_width. This is
|
||||||
// to ensure compatibility with the IEEE standard, which requires
|
// necessary to ensure compatibility with the IEEE standard, which
|
||||||
// unsized literals to be treated as having the same width as an
|
// requires unsized numbers to be treated as having the same width
|
||||||
// integer. The lossless width calculation is inadequate in this
|
// as an integer. The lossless width calculation is inadequate in
|
||||||
// case because coercing an operand to a different type means that
|
// this case because coercing an operand to a different type means
|
||||||
// the expression no longer obeys the normal rules of arithmetic.
|
// that the expression no longer obeys the normal rules of arithmetic.
|
||||||
//
|
//
|
||||||
// If mode is initialised to EXPAND instead of SIZED, the expression
|
// If mode is initialised to EXPAND instead of SIZED, the expression
|
||||||
// width will be calculated as the minimum width necessary to avoid
|
// width will be calculated as the minimum width necessary to avoid
|
||||||
// arithmetic overflow or underflow, even if it contains no unsized
|
// arithmetic overflow or underflow, even if it contains no unsized
|
||||||
// literals. mode will be changed LOSSLESS or UNSIZED as described
|
// literals. mode will be changed LOSSLESS or UPSIZE as described
|
||||||
// above. This supports a non-standard mode of expression width
|
// above. This supports a non-standard mode of expression width
|
||||||
// calculation.
|
// calculation.
|
||||||
//
|
//
|
||||||
// When the final value of mode is UNSIZED, the width returned by
|
// When the final value of mode is UPSIZE, the width returned by
|
||||||
// this method is the calculated lossless width, but the width
|
// this method is the calculated lossless width, but the width
|
||||||
// returned by a subsequent call to the expr_width method will be
|
// returned by a subsequent call to the expr_width method will be
|
||||||
// the final expression width.
|
// the final expression width.
|
||||||
|
|
|
||||||
54
elab_expr.cc
54
elab_expr.cc
|
|
@ -136,14 +136,14 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the mode is UNSIZED, make sure the final expression width is at
|
* If the mode is UPSIZE, make sure the final expression width is at
|
||||||
* least integer_width, but return the calculated lossless width to
|
* least integer_width, but return the calculated lossless width to
|
||||||
* the caller.
|
* the caller.
|
||||||
*/
|
*/
|
||||||
unsigned PExpr::fix_width_(width_mode_t mode)
|
unsigned PExpr::fix_width_(width_mode_t mode)
|
||||||
{
|
{
|
||||||
unsigned width = expr_width_;
|
unsigned width = expr_width_;
|
||||||
if ((mode == UNSIZED) && type_is_vectorable(expr_type_)
|
if ((mode == UPSIZE) && type_is_vectorable(expr_type_)
|
||||||
&& (width < integer_width))
|
&& (width < integer_width))
|
||||||
expr_width_ = integer_width;
|
expr_width_ = integer_width;
|
||||||
|
|
||||||
|
|
@ -265,7 +265,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
unsigned r_width = right_->test_width(des, scope, mode);
|
unsigned r_width = right_->test_width(des, scope, mode);
|
||||||
|
|
||||||
// If the width mode changed, retest the left operand, as it
|
// If the width mode changed, retest the left operand, as it
|
||||||
// may choose a different width if it is in an unsized context.
|
// may choose a different width if it is in a lossless context.
|
||||||
if ((mode >= LOSSLESS) && (saved_mode < LOSSLESS))
|
if ((mode >= LOSSLESS) && (saved_mode < LOSSLESS))
|
||||||
l_width = left_->test_width(des, scope, mode);
|
l_width = left_->test_width(des, scope, mode);
|
||||||
|
|
||||||
|
|
@ -293,17 +293,17 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
// calculation is unreliable and we need to make sure the
|
// calculation is unreliable and we need to make sure the
|
||||||
// final expression width is at least integer_width.
|
// final expression width is at least integer_width.
|
||||||
if ((mode == LOSSLESS) && (left_->has_sign() != right_->has_sign()))
|
if ((mode == LOSSLESS) && (left_->has_sign() != right_->has_sign()))
|
||||||
mode = UNSIZED;
|
mode = UPSIZE;
|
||||||
|
|
||||||
switch (op_) {
|
switch (op_) {
|
||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
if (mode != SIZED)
|
if (mode >= EXPAND)
|
||||||
expr_width_ += 1;
|
expr_width_ += 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
if (mode != SIZED)
|
if (mode >= EXPAND)
|
||||||
expr_width_ = l_width + r_width;
|
expr_width_ = l_width + r_width;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -575,8 +575,8 @@ unsigned PEBComp::test_width(Design*des, NetScope*scope, width_mode_t&)
|
||||||
unsigned r_width = right_->test_width(des, scope, mode);
|
unsigned r_width = right_->test_width(des, scope, mode);
|
||||||
|
|
||||||
// If the width mode changed, retest the left operand, as it
|
// If the width mode changed, retest the left operand, as it
|
||||||
// may choose a different width if it is in an unsized context.
|
// may choose a different width if it is in a lossless context.
|
||||||
if ((mode != SIZED) && (saved_mode == SIZED))
|
if ((mode >= LOSSLESS) && (saved_mode < LOSSLESS))
|
||||||
l_width = left_->test_width(des, scope, mode);
|
l_width = left_->test_width(des, scope, mode);
|
||||||
|
|
||||||
ivl_variable_type_t l_type = left_->expr_type();
|
ivl_variable_type_t l_type = left_->expr_type();
|
||||||
|
|
@ -590,14 +590,14 @@ unsigned PEBComp::test_width(Design*des, NetScope*scope, width_mode_t&)
|
||||||
if (type_is_vectorable(r_type) && (l_width > r_width))
|
if (type_is_vectorable(r_type) && (l_width > r_width))
|
||||||
r_width_ = l_width;
|
r_width_ = l_width;
|
||||||
|
|
||||||
// If the expression is unsized and smaller than the integer
|
// If the expression is lossless and smaller than the integer
|
||||||
// minimum, then tweak the size up.
|
// minimum, then tweak the size up.
|
||||||
// NOTE: I really would rather try to figure out what it would
|
// NOTE: I really would rather try to figure out what it would
|
||||||
// take to get expand the sub-expressions so that they are
|
// take to get expand the sub-expressions so that they are
|
||||||
// exactly the right width to behave just like infinite
|
// exactly the right width to behave just like infinite
|
||||||
// width. I suspect that adding 1 more is sufficient in all
|
// width. I suspect that adding 1 more is sufficient in all
|
||||||
// cases, but I'm not certain. Ideas?
|
// cases, but I'm not certain. Ideas?
|
||||||
if (mode != SIZED) {
|
if (mode >= EXPAND) {
|
||||||
if (type_is_vectorable(l_type) && (l_width_ < integer_width))
|
if (type_is_vectorable(l_type) && (l_width_ < integer_width))
|
||||||
l_width_ += 1;
|
l_width_ += 1;
|
||||||
if (type_is_vectorable(r_type) && (r_width_ < integer_width))
|
if (type_is_vectorable(r_type) && (r_width_ < integer_width))
|
||||||
|
|
@ -725,7 +725,7 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
expr_type_ = left_->expr_type();
|
expr_type_ = left_->expr_type();
|
||||||
signed_flag_ = left_->has_sign();
|
signed_flag_ = left_->has_sign();
|
||||||
|
|
||||||
if ((mode != SIZED) && type_is_vectorable(expr_type_)) {
|
if ((mode >= EXPAND) && type_is_vectorable(expr_type_)) {
|
||||||
// We need to make our best guess at the right operand
|
// We need to make our best guess at the right operand
|
||||||
// value, to minimise the calculated width. This is
|
// value, to minimise the calculated width. This is
|
||||||
// particularly important for the power operator...
|
// particularly important for the power operator...
|
||||||
|
|
@ -782,7 +782,7 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
// shift may do the same, as we don't yet know the final
|
// shift may do the same, as we don't yet know the final
|
||||||
// expression type.
|
// expression type.
|
||||||
if ((mode == LOSSLESS) && signed_flag_)
|
if ((mode == LOSSLESS) && signed_flag_)
|
||||||
mode = UNSIZED;
|
mode = UPSIZE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p': // **
|
case 'p': // **
|
||||||
|
|
@ -1059,7 +1059,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
|
||||||
min_width_ = expr->min_width();
|
min_width_ = expr->min_width();
|
||||||
signed_flag_ = (name[1] == 's');
|
signed_flag_ = (name[1] == 's');
|
||||||
|
|
||||||
if ((arg_mode != SIZED) && type_is_vectorable(expr_type_)) {
|
if ((arg_mode >= EXPAND) && type_is_vectorable(expr_type_)) {
|
||||||
if (mode < LOSSLESS)
|
if (mode < LOSSLESS)
|
||||||
mode = LOSSLESS;
|
mode = LOSSLESS;
|
||||||
if (expr_width_ < integer_width)
|
if (expr_width_ < integer_width)
|
||||||
|
|
@ -2864,8 +2864,8 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
min_width_ = expr_width_;
|
min_width_ = expr_width_;
|
||||||
signed_flag_ = par->has_sign();
|
signed_flag_ = par->has_sign();
|
||||||
|
|
||||||
if ((mode < LOSSLESS) && !par->has_width())
|
if (!par->has_width() && (mode < LOSSLESS))
|
||||||
mode = LOSSLESS;
|
mode = LOSSLESS;
|
||||||
|
|
||||||
return expr_width_;
|
return expr_width_;
|
||||||
}
|
}
|
||||||
|
|
@ -2879,8 +2879,12 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
min_width_ = expr_width_;
|
min_width_ = expr_width_;
|
||||||
signed_flag_ = true;
|
signed_flag_ = true;
|
||||||
|
|
||||||
if (mode < LOSSLESS)
|
if (gn_strict_expr_width_flag) {
|
||||||
mode = LOSSLESS;
|
expr_width_ = integer_width;
|
||||||
|
mode = UNSIZED;
|
||||||
|
} else if (mode < LOSSLESS) {
|
||||||
|
mode = LOSSLESS;
|
||||||
|
}
|
||||||
|
|
||||||
return expr_width_;
|
return expr_width_;
|
||||||
}
|
}
|
||||||
|
|
@ -4838,15 +4842,17 @@ unsigned PENumber::test_width(Design*, NetScope*, width_mode_t&mode)
|
||||||
{
|
{
|
||||||
expr_type_ = IVL_VT_LOGIC;
|
expr_type_ = IVL_VT_LOGIC;
|
||||||
expr_width_ = value_->len();
|
expr_width_ = value_->len();
|
||||||
|
min_width_ = expr_width_;
|
||||||
signed_flag_ = value_->has_sign();
|
signed_flag_ = value_->has_sign();
|
||||||
|
|
||||||
if (!value_->has_len() && !value_->is_single()) {
|
if (!value_->has_len() && !value_->is_single()) {
|
||||||
if (gn_strict_expr_width_flag)
|
if (gn_strict_expr_width_flag) {
|
||||||
expr_width_ = integer_width;
|
expr_width_ = integer_width;
|
||||||
else if (mode < LOSSLESS)
|
mode = UNSIZED;
|
||||||
mode = LOSSLESS;
|
} else if (mode < LOSSLESS) {
|
||||||
|
mode = LOSSLESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
min_width_ = expr_width_;
|
|
||||||
|
|
||||||
return expr_width_;
|
return expr_width_;
|
||||||
}
|
}
|
||||||
|
|
@ -4941,7 +4947,7 @@ unsigned PETernary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
unsigned fal_width = fal_->test_width(des, scope, mode);
|
unsigned fal_width = fal_->test_width(des, scope, mode);
|
||||||
|
|
||||||
// If the width mode changed, retest the true clause, as it
|
// If the width mode changed, retest the true clause, as it
|
||||||
// may choose a different width if it is in an unsized context.
|
// may choose a different width if it is in a lossless context.
|
||||||
if ((mode >= LOSSLESS) && (saved_mode < LOSSLESS)) {
|
if ((mode >= LOSSLESS) && (saved_mode < LOSSLESS)) {
|
||||||
tru_width = tru_->test_width(des, scope, mode);
|
tru_width = tru_->test_width(des, scope, mode);
|
||||||
}
|
}
|
||||||
|
|
@ -4976,7 +4982,7 @@ unsigned PETernary::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
// calculation is unreliable and we need to make sure the
|
// calculation is unreliable and we need to make sure the
|
||||||
// final expression width is at least integer_width.
|
// final expression width is at least integer_width.
|
||||||
if ((mode == LOSSLESS) && (tru_->has_sign() != fal_->has_sign()))
|
if ((mode == LOSSLESS) && (tru_->has_sign() != fal_->has_sign()))
|
||||||
mode = UNSIZED;
|
mode = UPSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug_elaborate)
|
if (debug_elaborate)
|
||||||
|
|
|
||||||
|
|
@ -859,7 +859,7 @@ NetExpr* elab_sys_task_arg(Design*des, NetScope*scope, perm_string name,
|
||||||
// determine the exact width required to hold the result.
|
// determine the exact width required to hold the result.
|
||||||
// But leave literal numbers exactly as the user supplied
|
// But leave literal numbers exactly as the user supplied
|
||||||
// them.
|
// them.
|
||||||
if ((mode != PExpr::SIZED) && !dynamic_cast<PENumber*>(pe))
|
if ((mode >= PExpr::LOSSLESS) && !dynamic_cast<PENumber*>(pe))
|
||||||
ce->trim();
|
ce->trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue