diff --git a/PExpr.cc b/PExpr.cc index 70c73a978..87fa6ad39 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -28,6 +28,8 @@ PExpr::PExpr() { + expr_type_ = IVL_VT_NO_TYPE; + has_sign_ = false; } PExpr::~PExpr() diff --git a/PExpr.h b/PExpr.h index a3da795a3..7237cbc2f 100644 --- a/PExpr.h +++ b/PExpr.h @@ -73,7 +73,13 @@ class PExpr : public LineInfo { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); + + // After the test_width method is complete, these methods + // return valid results. + ivl_variable_type_t expr_type() const { return expr_type_; } + unsigned expr_width() const { return expr_width_; } + bool has_sign() const { return has_sign_; } // During the elaborate_sig phase, we may need to scan // expressions to find implicit net declarations. @@ -134,6 +140,12 @@ class PExpr : public LineInfo { // of expressions. virtual bool is_constant(Module*) const; + protected: + // The derived class test_width methods should fill these in. + ivl_variable_type_t expr_type_; + unsigned expr_width_; + bool has_sign_; + private: // not implemented PExpr(const PExpr&); PExpr& operator= (const PExpr&); @@ -218,7 +230,7 @@ class PEFNumber : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -244,7 +256,7 @@ class PEIdent : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); virtual bool elaborate_sig(Design*des, NetScope*scope) const; @@ -360,7 +372,7 @@ class PENumber : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); virtual NetEConst*elaborate_expr(Design*des, NetScope*, int expr_width, bool) const; @@ -397,7 +409,7 @@ class PEString : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); virtual NetEConst*elaborate_expr(Design*des, NetScope*, int expr_width, bool) const; @@ -421,7 +433,7 @@ class PEUnary : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); virtual bool elaborate_sig(Design*des, NetScope*scope) const; @@ -450,7 +462,7 @@ class PEBinary : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); virtual bool elaborate_sig(Design*des, NetScope*scope) const; @@ -491,7 +503,7 @@ class PEBComp : public PEBinary { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&flag) const; + bool&flag); NetExpr* elaborate_expr(Design*des, NetScope*scope, int expr_width, bool sys_task_arg) const; @@ -506,7 +518,7 @@ class PEBShift : public PEBinary { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&flag) const; + bool&flag); virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; }; @@ -527,7 +539,7 @@ class PETernary : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); virtual bool elaborate_sig(Design*des, NetScope*scope) const; @@ -571,7 +583,7 @@ class PECallFunction : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); private: pform_name_t path_; @@ -584,7 +596,7 @@ class PECallFunction : public PExpr { unsigned test_width_sfunc_(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const; + bool&unsized_flag); }; #endif diff --git a/PGate.h b/PGate.h index e9f447451..b52763ee5 100644 --- a/PGate.h +++ b/PGate.h @@ -80,7 +80,7 @@ class PGate : public LineInfo { bool as_net_flag =false) const; unsigned pin_count() const { return pins_? pins_->count() : 0; } - const PExpr*pin(unsigned idx) const { return (*pins_)[idx]; } + PExpr*pin(unsigned idx) const { return (*pins_)[idx]; } strength_t strength0() const; strength_t strength1() const; diff --git a/Statement.h b/Statement.h index d817ff7a2..5662a9ce6 100644 --- a/Statement.h +++ b/Statement.h @@ -99,7 +99,7 @@ class PAssign_ : public Statement { virtual ~PAssign_() =0; const PExpr* lval() const { return lval_; } - const PExpr* rval() const { return rval_; } + PExpr* rval() const { return rval_; } protected: NetAssign_* elaborate_lval(Design*, NetScope*scope) const; diff --git a/elab_expr.cc b/elab_expr.cc index f54d9a47a..d73863d76 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -44,12 +44,25 @@ bool type_is_vectorable(ivl_variable_type_t type) NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_variable_type_t data_type_lv, int expr_wid_lv, - const PExpr*expr) + PExpr*expr) { - int expr_wid = 0; - bool unsized_flag = false; + bool unsized_flag = type_is_vectorable(data_type_lv)? true : false; ivl_variable_type_t rval_type = IVL_VT_NO_TYPE; + /* 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); + + if (debug_elaborate) { + cerr << expr->get_fileline() << ": debug: r-value tested " + << "type=" << rval_type + << ", width=" << expr_wid + << ", min=" << expr_wid_lv + << ", unsized_flag=" << (unsized_flag?"true":"false") << endl; + } + switch (data_type_lv) { case IVL_VT_REAL: unsized_flag = true; @@ -58,19 +71,6 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, break; case IVL_VT_BOOL: case IVL_VT_LOGIC: - /* 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. */ - expr_wid = expr->test_width(des, scope, expr_wid_lv, expr_wid_lv, rval_type, unsized_flag); - - if (debug_elaborate) { - cerr << expr->get_fileline() << ": debug: r-value tested " - << "width is " << expr_wid - << ", min=" << expr_wid_lv - << ", unsized_flag=" << (unsized_flag?"true":"false") << endl; - } - break; case IVL_VT_VOID: case IVL_VT_NO_TYPE: @@ -90,7 +90,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, */ unsigned PExpr::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&, bool&) const + ivl_variable_type_t&, bool&) { if (debug_elaborate) { cerr << get_fileline() << ": debug: test_width defaults to " @@ -113,7 +113,7 @@ NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, int, bool) const unsigned PEBinary::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const + bool&unsized_flag) { ivl_variable_type_t expr_type_left = IVL_VT_NO_TYPE; ivl_variable_type_t expr_type_right= IVL_VT_NO_TYPE; @@ -126,23 +126,23 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, if (flag_right && !flag_left) { flag_left = flag_right; - wid_left = left_->test_width(des, scope, min, 0, expr_type_right, flag_right); + wid_left = left_->test_width(des, scope, min, 0, expr_type_left, flag_right); } if (flag_left || flag_right) unsized_flag = true; if (expr_type_left == IVL_VT_REAL || expr_type_right == IVL_VT_REAL) - expr_type = IVL_VT_REAL; + expr_type_ = IVL_VT_REAL; else if (expr_type_left==IVL_VT_LOGIC || expr_type_right==IVL_VT_LOGIC) - expr_type = IVL_VT_LOGIC; + expr_type_ = IVL_VT_LOGIC; else - expr_type = IVL_VT_BOOL; + expr_type_ = IVL_VT_BOOL; switch (op_) { case '+': case '-': - if (unsized_flag && type_is_vectorable(expr_type)) { + if (unsized_flag && type_is_vectorable(expr_type_)) { wid_left += 1; wid_right += 1; } @@ -172,7 +172,13 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, break; } - return min; + if (type_is_vectorable(expr_type_)) + expr_width_ = min; + else + expr_width_ = 1; + + expr_type = expr_type_; + return expr_width_; } /* @@ -697,7 +703,7 @@ NetExpr* PEBinary::elaborate_expr_base_add_(Design*des, unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, ivl_variable_type_t&expr_type, - bool&) const + bool&) { expr_type = IVL_VT_LOGIC; return 1; @@ -748,7 +754,7 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, unsigned PEBShift::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const + bool&unsized_flag) { unsigned wid_left = left_->test_width(des,scope,min, 0, expr_type, unsized_flag); @@ -794,7 +800,7 @@ NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope, unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const + bool&unsized_flag) { perm_string name = peek_tail_name(path_); @@ -810,14 +816,33 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, return wid; } + // Run through the arguments of the system function and make + // sure their widths/types are calculated. They are all self- + // determined. + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { + PExpr*expr = parms_[idx]; + ivl_variable_type_t sub_type = IVL_VT_NO_TYPE; + bool flag = false; + unsigned wid = expr->test_width(des,scope,0,0,sub_type,flag); + if (debug_elaborate) + cerr << get_fileline() << ": debug: test_width" + << " of " << name << " argument " << idx+1 + << " returns type=" << sub_type + << ", wid=" << wid << endl; + } + if (name=="$sizeof" || name=="$bits") { if (debug_elaborate) cerr << get_fileline() << ": debug: test_width" << " of $sizeof/$bits returns test_width" << " of compiler integer." << endl; - expr_type = IVL_VT_BOOL; - return integer_width; + expr_type_ = IVL_VT_BOOL; + expr_width_= integer_width; + has_sign_ = false; + + expr_type = expr_type_; + return expr_width_; } if (name=="$is_signed") { @@ -826,8 +851,10 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, << " of $is_signed returns test_width" << " of 1." << endl; - expr_type = IVL_VT_BOOL; - return 1; + expr_type_ = IVL_VT_BOOL; + expr_width_ = 1; + expr_type = expr_type_; + return expr_width_; } /* Get the return type of the system function by looking it up @@ -835,22 +862,24 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, const struct sfunc_return_type*sfunc_info = lookup_sys_func(peek_tail_name(path_)); - expr_type = sfunc_info->type; - unsigned wid = sfunc_info->wid; + expr_type_ = sfunc_info->type; + expr_width_ = sfunc_info->wid; + + expr_type = expr_type_; if (debug_elaborate) cerr << get_fileline() << ": debug: test_width " << "of system function " << name - << " returns wid=" << wid - << ", type=" << expr_type << "." << endl; + << " returns wid=" << expr_width_ + << ", type=" << expr_type_ << "." << endl; - return wid; + return expr_width_; } unsigned PECallFunction::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const + bool&unsized_flag) { if (peek_tail_name(path_)[0] == '$') return test_width_sfunc_(des, scope, min, lval, expr_type, unsized_flag); @@ -1312,10 +1341,14 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, unsigned PEFNumber::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const + bool&unsized_flag) { - expr_type = IVL_VT_REAL; + expr_type_ = IVL_VT_REAL; + expr_width_ = 1; + has_sign_ = true; unsized_flag = true; + + expr_type = expr_type_; return 1; } @@ -1342,11 +1375,19 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope, ivl_assert(*this, index_tail.sel == index_component_t::SEL_PART); ivl_assert(*this, index_tail.msb && index_tail.lsb); + ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE; + bool tmp_flag = false; + int msb_wid = index_tail.msb->test_width(des, scope, 0, 0, tmp_type, tmp_flag); + + tmp_type = IVL_VT_NO_TYPE; + tmp_flag = false; + int lsb_wid = index_tail.lsb->test_width(des, scope, 0, 0, tmp_type, tmp_flag); + /* This handles part selects. In this case, there are two bit select expressions, and both must be constant. Evaluate them and pass the results back to the caller. */ - NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, -1); + NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, lsb_wid); NetEConst*lsb_c = dynamic_cast(lsb_ex); if (lsb_c == 0) { cerr << index_tail.lsb->get_fileline() << ": error: " @@ -1359,7 +1400,7 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope, return false; } - NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, -1); + NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, msb_wid); NetEConst*msb_c = dynamic_cast(msb_ex); if (msb_c == 0) { cerr << index_tail.msb->get_fileline() << ": error: " @@ -1458,7 +1499,7 @@ bool PEIdent::calculate_param_range_(Design*des, NetScope*scope, unsigned PEIdent::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const + bool&unsized_flag) { NetNet* net = 0; const NetExpr*par = 0; @@ -1468,14 +1509,21 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, symbol_search(des, scope, path_, net, par, eve, ex1, ex2); + if (net != 0) + expr_type_ = net->data_type(); + + expr_type = expr_type; + // If there is a part/bit select expression, then process it // here. This constrains the results no matter what kind the // name is. const name_component_t&name_tail = path_.back(); index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; - if (!name_tail.index.empty()) - use_sel = name_tail.index.back().sel; + if (!name_tail.index.empty()) { + const index_component_t&index_tail = name_tail.index.back(); + use_sel = index_tail.sel; + } unsigned use_width = UINT_MAX; switch (use_sel) { @@ -1506,15 +1554,18 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, // The width of a signal expression is the width of the signal. if (net != 0) { - expr_type = net->data_type(); - return max(net->vector_width(), (unsigned long)min); + expr_type_ = net->data_type(); + expr_width_= max(net->vector_width(), (unsigned long)min); + expr_type = expr_type_; + return expr_width_; } // The width of a parameter name is the width of the range for // the parameter name, if a range is declared. Otherwise, the // width is undefined. if (par != 0) { - expr_type = par->expr_type(); + expr_type_ = par->expr_type(); + expr_type = expr_type_; if (ex1) { ivl_assert(*this, ex2); const NetEConst*ex1_const = dynamic_cast (ex1); @@ -1524,19 +1575,22 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, long msb = ex1_const->value().as_long(); long lsb = ex2_const->value().as_long(); if (msb >= lsb) - return msb - lsb + 1; + expr_width_ = msb - lsb + 1; else - return lsb - msb + 1; + expr_width_ = lsb - msb + 1; + return expr_width_; } // This is a parameter. If it is sized (meaning it was // declared with range expresions) then the range // expressions would have been caught above. So if we // got there there we know this is an unsized constant. + expr_width_ = par->expr_width(); unsized_flag = true; - return par->expr_width(); + return expr_width_; } + expr_width_ = min; return min; } @@ -2392,9 +2446,9 @@ 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, - bool&unsized_flag) const + bool&unsized_flag) { - expr_type = IVL_VT_LOGIC; + expr_type_ = IVL_VT_LOGIC; unsigned use_wid = value_->len(); if (min > use_wid) use_wid = min; @@ -2405,6 +2459,8 @@ unsigned PENumber::test_width(Design*, NetScope*, if (lval > 0 && lval < use_wid) use_wid = lval; + expr_type = expr_type_; + expr_width_ = use_wid; return use_wid; } @@ -2435,7 +2491,7 @@ NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, unsigned PEString::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const + bool&unsized_flag) { expr_type = IVL_VT_BOOL; unsigned use_wid = text_? 8*strlen(text_) : 0; @@ -2456,7 +2512,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, - bool&flag) const + bool&flag) { ivl_variable_type_t tru_type = IVL_VT_NO_TYPE; unsigned tru_wid = tru_->test_width(des, scope, min, lval, tru_type,flag); @@ -2477,13 +2533,16 @@ unsigned PETernary::test_width(Design*des, NetScope*scope, } if (tru_type == IVL_VT_REAL || fal_type == IVL_VT_REAL) - expr_type = IVL_VT_REAL; + expr_type_ = IVL_VT_REAL; else if (tru_type == IVL_VT_LOGIC || fal_type == IVL_VT_LOGIC) - expr_type = IVL_VT_LOGIC; + expr_type_ = IVL_VT_LOGIC; else - expr_type = tru_type; - - return max(tru_wid,fal_wid); + expr_type_ = tru_type; + + expr_width_ = max(tru_wid,fal_wid); + + expr_type = expr_type_; + return expr_width_; } bool NetETernary::test_operand_compat(ivl_variable_type_t l, @@ -2520,13 +2579,11 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, int use_wid = expr_wid >= 0? expr_wid : 0; if (expr_wid < 0) { - bool flag = expr_wid == -2; - ivl_variable_type_t expr_type = IVL_VT_NO_TYPE; - use_wid = this->test_width(des, scope, 0, 0, expr_type, flag); + use_wid = expr_width(); if (debug_elaborate) cerr << get_fileline() << ": debug: " << "Self-sized ternary chooses wid="<< use_wid - << ", type=" << expr_type + << ", type=" << expr_type() << endl; ivl_assert(*this, use_wid > 0); } @@ -2611,7 +2668,7 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, unsigned PEUnary::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type, - bool&unsized_flag) const + bool&unsized_flag) { switch (op_) { case '!': diff --git a/elaborate.cc b/elaborate.cc index 59130d660..4b8056411 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2321,12 +2321,30 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { PExpr*ex = parm(idx); - eparms[idx] = ex? ex->elaborate_expr(des, scope, -1, true) : 0; + if (ex != 0) { + ivl_variable_type_t use_type; + bool flag = false; + int use_wid = ex->test_width(des,scope,0,0, use_type, flag); + if (debug_elaborate) + cerr << ex->get_fileline() << ": debug: " + << "Argument " << (idx+1) + << " of system task tests its width as " << use_wid + << ", type=" << use_type + << ", unsized_flag=" << flag << endl; - /* Attempt to pre-evaluate the parameters. It may be - possible to at least partially reduce the - expression. */ - if (eparms[idx]) eval_expr(eparms[idx]); + // If the argument expression is unsized, then + // elaborate as self-determined *lossless* instead + // of sized. + if (flag==true) + use_wid = -2; + + eparms[idx] = ex->elaborate_expr(des, scope, use_wid, true); + if (eparms[idx]) + eval_expr(eparms[idx]); + + } else { + eparms[idx] = 0; + } } NetSTask*cur = new NetSTask(peek_tail_name(path_), eparms); diff --git a/netmisc.h b/netmisc.h index 7e31b37fa..97792d8f7 100644 --- a/netmisc.h +++ b/netmisc.h @@ -157,7 +157,7 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope, */ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_variable_type_t data_type_lv, - int expr_wid_lv, const PExpr*expr); + int expr_wid_lv, PExpr*expr); /* * This procedure elaborates an expression and if the elaboration is * successful the original expression is replaced with the new one.