diff --git a/PExpr.h b/PExpr.h index 7f82b1c6b..889f53f48 100644 --- a/PExpr.h +++ b/PExpr.h @@ -544,7 +544,7 @@ class PEBinary : public PExpr { const NetExpr* decay, Link::strength_t drive0, Link::strength_t drive1) const; - virtual NetEBinary*elaborate_expr(Design*des, NetScope*, + virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const; @@ -554,8 +554,8 @@ class PEBinary : public PExpr { PExpr*left_; PExpr*right_; - NetEBinary*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; - NetEBinary*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; + NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; + NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp); @@ -621,8 +621,8 @@ class PEBComp : public PEBinary { unsigned min, unsigned lval, bool&flag) const; - NetEBinary* elaborate_expr(Design*des, NetScope*scope, - int expr_width, bool sys_task_arg) const; + NetExpr* elaborate_expr(Design*des, NetScope*scope, + int expr_width, bool sys_task_arg) const; }; class PEBShift : public PEBinary { diff --git a/elab_expr.cc b/elab_expr.cc index e750f9203..5b9b13a18 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -96,7 +96,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, * and right sides, and creating one of a variety of different NetExpr * types. */ -NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope, +NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope, int expr_wid, bool) const { assert(left_); @@ -110,7 +110,7 @@ NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope, return 0; } - NetEBinary*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid); + NetExpr*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid); return tmp; } @@ -128,7 +128,7 @@ void PEBinary::suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp) lp->cast_signed(false); } -NetEBinary* PEBinary::elaborate_eval_expr_base_(Design*des, +NetExpr* PEBinary::elaborate_eval_expr_base_(Design*des, NetExpr*lp, NetExpr*rp, int expr_wid) const @@ -146,7 +146,7 @@ NetEBinary* PEBinary::elaborate_eval_expr_base_(Design*des, * operands are elaborated as necessary, and all I need to do is make * the correct NetEBinary object and connect the parameters. */ -NetEBinary* PEBinary::elaborate_expr_base_(Design*des, +NetExpr* PEBinary::elaborate_expr_base_(Design*des, NetExpr*lp, NetExpr*rp, int expr_wid) const { @@ -157,7 +157,7 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des, << *this << " expr_wid=" << expr_wid << endl; } - NetEBinary*tmp; + NetExpr*tmp; switch (op_) { default: @@ -200,6 +200,56 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des, break; case 'l': // << + if (NetEConst*lpc = dynamic_cast (lp)) { + if (NetEConst*rpc = dynamic_cast (rp)) { + // Handle the super-special case that both + // operands are constants. Precalculate the + // entire value here. + verinum lpval = lpc->value(); + unsigned shift = rpc->value().as_ulong(); + verinum result = lpc->value() << shift; + // If the l-value has explicit size, or + // there is a context determined size, use that. + if (lpval.has_len() || expr_wid > 0) { + int use_len = lpval.len(); + if (expr_wid < use_len) + use_len = expr_wid; + result = verinum(result, lpval.len()); + } + + tmp = new NetEConst(result); + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Precalculate " << *this + << " to constant " << *tmp << endl; + + } else { + // Handle the special case that the left + // operand is constant. If it is unsized, we + // may have to expand it to an integer width. + verinum lpval = lpc->value(); + if (lpval.len() < integer_width && !lpval.has_len()) { + lpval = verinum(lpval, integer_width); + lpc = new NetEConst(lpval); + lpc->set_line(*lp); + } + + tmp = new NetEBShift(op_, lpc, rp); + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Adjust " << *this + << " to this " << *tmp + << " to allow for integer widths." << endl; + } + + } else { + // Left side is not constant, so handle it the + // default way. + tmp = new NetEBShift(op_, lp, rp); + } + tmp->set_line(*this); + break; + case 'r': // >> case 'R': // >>> tmp = new NetEBShift(op_, lp, rp); @@ -269,8 +319,8 @@ unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, bool&) const return 1; } -NetEBinary* PEBComp::elaborate_expr(Design*des, NetScope*scope, - int expr_width, bool sys_task_arg) const +NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, + int expr_width, bool sys_task_arg) const { assert(left_); assert(right_); diff --git a/elab_pexpr.cc b/elab_pexpr.cc index 804a29b65..a3d398a47 100644 --- a/elab_pexpr.cc +++ b/elab_pexpr.cc @@ -53,7 +53,7 @@ NetExpr*PEBinary::elaborate_pexpr (Design*des, NetScope*scope) const return 0; } - NetEBinary*tmp = elaborate_expr_base_(des, lp, rp, -2); + NetExpr*tmp = elaborate_expr_base_(des, lp, rp, -2); return tmp; }