Handle ternary expressions with mixed argument types.
If the true and false alternatives are mixed types, then vectored arguments are treated as if in a self-determined context then cast to REAL.
This commit is contained in:
parent
8eb7e4b3d4
commit
707a3ebe27
4
PExpr.h
4
PExpr.h
|
|
@ -621,6 +621,10 @@ class PETernary : public PExpr {
|
|||
virtual NetETernary*elaborate_pexpr(Design*des, NetScope*sc) const;
|
||||
virtual verinum* eval_const(Design*des, NetScope*sc) const;
|
||||
|
||||
private:
|
||||
NetExpr* elab_and_eval_alternative_(Design*des, NetScope*scope,
|
||||
PExpr*expr, int use_wid) const;
|
||||
|
||||
private:
|
||||
PExpr*expr_;
|
||||
PExpr*tru_;
|
||||
|
|
|
|||
70
elab_expr.cc
70
elab_expr.cc
|
|
@ -83,20 +83,22 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
|
|||
ivl_variable_type_t data_type_lv, int expr_wid_lv,
|
||||
PExpr*expr)
|
||||
{
|
||||
bool unsized_flag = type_is_vectorable(data_type_lv)? false : true;
|
||||
ivl_variable_type_t rval_type = IVL_VT_NO_TYPE;
|
||||
bool unsized_flag = type_is_vectorable(data_type_lv)? false : true;
|
||||
unsigned use_lval_wid = type_is_vectorable(data_type_lv)? expr_wid_lv : 0;
|
||||
unsigned use_min_wid = expr_wid_lv;
|
||||
|
||||
/* Find out what the r-value width is going to be. We
|
||||
guess it will be the l-value width, but it may turn
|
||||
out to be something else based on self-determined
|
||||
widths inside. */
|
||||
int expr_wid = expr->test_width(des, scope, expr_wid_lv, expr_wid_lv, rval_type, unsized_flag);
|
||||
ivl_variable_type_t rval_type = IVL_VT_NO_TYPE;
|
||||
int expr_wid = expr->test_width(des, scope, use_min_wid, use_lval_wid, rval_type, unsized_flag);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << expr->get_fileline() << ": debug: r-value tested "
|
||||
<< "type=" << rval_type
|
||||
<< ", width=" << expr_wid
|
||||
<< ", min=" << expr_wid_lv
|
||||
<< ", min=" << use_min_wid
|
||||
<< ", unsized_flag=" << (unsized_flag?"true":"false") << endl;
|
||||
}
|
||||
|
||||
|
|
@ -2799,7 +2801,7 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
|
|||
|
||||
unsigned PENumber::test_width(Design*, NetScope*,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type__,
|
||||
ivl_variable_type_t&use_expr_type,
|
||||
bool&unsized_flag)
|
||||
{
|
||||
expr_type_ = IVL_VT_LOGIC;
|
||||
|
|
@ -2813,7 +2815,7 @@ unsigned PENumber::test_width(Design*, NetScope*,
|
|||
if (lval > 0 && lval < use_wid)
|
||||
use_wid = lval;
|
||||
|
||||
expr_type__ = expr_type_;
|
||||
use_expr_type = expr_type_;
|
||||
expr_width_ = use_wid;
|
||||
return use_wid;
|
||||
}
|
||||
|
|
@ -2866,7 +2868,7 @@ NetEConst* PEString::elaborate_expr(Design*des, NetScope*,
|
|||
|
||||
unsigned PETernary::test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type__,
|
||||
ivl_variable_type_t&use_expr_type,
|
||||
bool&flag)
|
||||
{
|
||||
// The condition of the ternary is self-determined, but we
|
||||
|
|
@ -2893,16 +2895,32 @@ unsigned PETernary::test_width(Design*des, NetScope*scope,
|
|||
tru_wid = tru_->test_width(des, scope, max(min,fal_wid), lval, tru_type, flag);
|
||||
}
|
||||
|
||||
if (tru_type == IVL_VT_REAL || fal_type == IVL_VT_REAL)
|
||||
// If either of the alternatives is IVL_VT_REAL, then the
|
||||
// expression as a whole is IVL_VT_REAL. Otherwise, if either
|
||||
// of the alternatives is IVL_VT_LOGIC, then the expression as
|
||||
// a whole is IVL_VT_LOGIC. The fallback assumes that the
|
||||
// types are the same and we take that.
|
||||
if (tru_type == IVL_VT_REAL || fal_type == IVL_VT_REAL) {
|
||||
expr_type_ = IVL_VT_REAL;
|
||||
else if (tru_type == IVL_VT_LOGIC || fal_type == IVL_VT_LOGIC)
|
||||
expr_width_ = 1;
|
||||
} else if (tru_type == IVL_VT_LOGIC || fal_type == IVL_VT_LOGIC) {
|
||||
expr_type_ = IVL_VT_LOGIC;
|
||||
else
|
||||
expr_width_ = max(tru_wid,fal_wid);
|
||||
} else {
|
||||
ivl_assert(*this, tru_type == fal_type);
|
||||
expr_type_ = tru_type;
|
||||
expr_width_ = max(tru_wid,fal_wid);
|
||||
}
|
||||
|
||||
expr_width_ = max(tru_wid,fal_wid);
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Ternary expression type=" << expr_type_
|
||||
<< ", width=" << expr_width_
|
||||
<< ", unsized_flag=" << flag
|
||||
<< " (tru_type=" << tru_type
|
||||
<< ", fal_type=" << fal_type << ")" << endl;
|
||||
|
||||
expr_type__ = expr_type_;
|
||||
use_expr_type = expr_type_;
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
|
|
@ -2982,8 +3000,8 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
|
|||
<< " of expression: " << *this << endl;
|
||||
}
|
||||
ivl_assert(*this, use_wid > 0);
|
||||
NetExpr*tru = elab_and_eval(des, scope, tru_, use_wid);
|
||||
return pad_to_width(tru, use_wid, *this);
|
||||
NetExpr*tmp = elab_and_eval_alternative_(des, scope, tru_, use_wid);
|
||||
return pad_to_width(tmp, use_wid, *this);
|
||||
}
|
||||
|
||||
// Condition is constant FALSE, so we only need the
|
||||
|
|
@ -3000,21 +3018,21 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
|
|||
<< " of expression: " << *this << endl;
|
||||
}
|
||||
ivl_assert(*this, use_wid > 0);
|
||||
NetExpr*fal = elab_and_eval(des, scope, fal_, use_wid);
|
||||
return pad_to_width(fal, use_wid, *this);
|
||||
NetExpr*tmp = elab_and_eval_alternative_(des, scope, fal_, use_wid);
|
||||
return pad_to_width(tmp, use_wid, *this);
|
||||
}
|
||||
|
||||
// X and Z conditions need to blend both results, so we
|
||||
// can't short-circuit.
|
||||
}
|
||||
|
||||
NetExpr*tru = elab_and_eval(des, scope, tru_, use_wid);
|
||||
NetExpr*tru = elab_and_eval_alternative_(des, scope, tru_, use_wid);
|
||||
if (tru == 0) {
|
||||
delete con;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*fal = elab_and_eval(des, scope, fal_, use_wid);
|
||||
NetExpr*fal = elab_and_eval_alternative_(des, scope, fal_, use_wid);
|
||||
if (fal == 0) {
|
||||
delete con;
|
||||
delete tru;
|
||||
|
|
@ -3042,6 +3060,22 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
|
|||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* When elaborating the true or false alternative expression of a
|
||||
* ternary, take into account the overall expression type. If the type
|
||||
* is not vectorable, then the alternative expression is evaluated as
|
||||
* self-determined.
|
||||
*/
|
||||
NetExpr* PETernary::elab_and_eval_alternative_(Design*des, NetScope*scope,
|
||||
PExpr*expr, int use_wid) const
|
||||
{
|
||||
if (type_is_vectorable(expr->expr_type()) && !type_is_vectorable(expr_type_)) {
|
||||
return elab_and_eval(des, scope, expr, -1);
|
||||
}
|
||||
|
||||
return elab_and_eval(des, scope, expr, use_wid);
|
||||
}
|
||||
|
||||
unsigned PEUnary::test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type__,
|
||||
|
|
|
|||
|
|
@ -1484,7 +1484,9 @@ NetExpr* NetETernary::eval_tree(int prune_to_width)
|
|||
<< "constant condition value: ";
|
||||
print_ternary_cond(cond_);
|
||||
cerr << get_fileline() << ": : Blending real cases "
|
||||
<< "to get " << val << endl;
|
||||
<< "true=" << tv.as_double()
|
||||
<< ", false=" << fv.as_double()
|
||||
<< ", to get " << val << endl;
|
||||
}
|
||||
|
||||
NetECReal*rc = new NetECReal(val);
|
||||
|
|
|
|||
|
|
@ -1184,12 +1184,21 @@ NetNet* NetETernary::synthesize(Design *des, NetScope*scope, NetExpr*root)
|
|||
osig->data_type(expr_type());
|
||||
osig->local_flag(true);
|
||||
|
||||
/* Make sure both value operands are the right width. */
|
||||
tsig = crop_to_width(des, pad_to_width(des, tsig, width, *this), width);
|
||||
fsig = crop_to_width(des, pad_to_width(des, fsig, width, *this), width);
|
||||
/* Make sure the types match. */
|
||||
if (expr_type() == IVL_VT_REAL) {
|
||||
tsig = cast_to_real(des, scope, tsig);
|
||||
fsig = cast_to_real(des, scope, fsig);
|
||||
|
||||
}
|
||||
|
||||
/* Make sure both value operands are the right width. */
|
||||
if (type_is_vectorable(expr_type())) {
|
||||
tsig = crop_to_width(des, pad_to_width(des, tsig, width, *this), width);
|
||||
fsig = crop_to_width(des, pad_to_width(des, fsig, width, *this), width);
|
||||
ivl_assert(*this, width == tsig->vector_width());
|
||||
ivl_assert(*this, width == fsig->vector_width());
|
||||
}
|
||||
|
||||
assert(width == tsig->vector_width());
|
||||
assert(width == fsig->vector_width());
|
||||
|
||||
perm_string oname = csig->scope()->local_symbol();
|
||||
NetMux *mux = new NetMux(csig->scope(), oname, width,
|
||||
|
|
|
|||
15
netlist.cc
15
netlist.cc
|
|
@ -2270,11 +2270,16 @@ ivl_variable_type_t NetESignal::expr_type() const
|
|||
NetETernary::NetETernary(NetExpr*c, NetExpr*t, NetExpr*f)
|
||||
: cond_(c), true_val_(t), false_val_(f)
|
||||
{
|
||||
// use widest result
|
||||
if (true_val_->expr_width() > false_val_->expr_width())
|
||||
expr_width(true_val_->expr_width());
|
||||
else
|
||||
expr_width(false_val_->expr_width());
|
||||
if (type_is_vectorable(expr_type())) {
|
||||
// use widest result
|
||||
if (true_val_->expr_width() > false_val_->expr_width())
|
||||
expr_width(true_val_->expr_width());
|
||||
else
|
||||
expr_width(false_val_->expr_width());
|
||||
} else {
|
||||
expr_width(1);
|
||||
}
|
||||
|
||||
cast_signed(c->has_sign() && t->has_sign() && f->has_sign());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue