diff --git a/PExpr.h b/PExpr.h index 4d1aa9007..e859402f6 100644 --- a/PExpr.h +++ b/PExpr.h @@ -376,7 +376,7 @@ class PEBinary : public PExpr { unsigned long decay, Link::strength_t drive0, Link::strength_t drive1) const; - virtual NetEBinary*elaborate_expr(Design*des, NetScope*, + virtual NetExpr*elaborate_expr(Design*des, NetScope*, bool sys_task_arg =false) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; virtual verinum* eval_const(const Design*des, const NetScope*sc) const; @@ -386,7 +386,7 @@ class PEBinary : public PExpr { PExpr*left_; PExpr*right_; - NetEBinary*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp) const; + NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp) const; NetNet* elaborate_net_add_(Design*des, NetScope*scope, unsigned lwidth, diff --git a/elab_expr.cc b/elab_expr.cc index ea112eff4..50ccef2d6 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -43,7 +43,7 @@ NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, bool) const * and right sides, and creating one of a variety of different NetExpr * types. */ -NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope, bool) const +NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope, bool) const { assert(left_); assert(right_); @@ -73,7 +73,7 @@ NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope, bool) const } } - NetEBinary*tmp = elaborate_expr_base_(des, lp, rp); + NetExpr*tmp = elaborate_expr_base_(des, lp, rp); return tmp; } @@ -82,11 +82,11 @@ NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope, bool) const * 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*lp, NetExpr*rp) const +NetExpr* PEBinary::elaborate_expr_base_(Design*des, + NetExpr*lp, NetExpr*rp) const { bool flag; - NetEBinary*tmp; + NetExpr*tmp; switch (op_) { default: @@ -112,6 +112,51 @@ 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, use that. + if (lpval.has_len()) { + result = verinum(result, lpval.len()); + } + + tmp = new NetEConst(result); + if (debug_elaborate) + cerr << get_line() << ": 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() < 32 && !lpval.has_len()) { + lpval = verinum(lpval, 32); + lpc = new NetEConst(lpval); + lpc->set_line(*lp); + } + + tmp = new NetEBShift(op_, lpc, rp); + if (debug_elaborate) + cerr << get_line() << ": 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); diff --git a/elab_pexpr.cc b/elab_pexpr.cc index ba9730e96..f65e660bb 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); + NetExpr*tmp = elaborate_expr_base_(des, lp, rp); return tmp; }