From 82143edf2ca09e216451718a770b7f2567f7d97c Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 28 Nov 2008 14:40:25 -0800 Subject: [PATCH] Rework shift and power PExpr nodes for their special needs. The power (**) and shift operators are different from other binary operators because their expression width calculations rely only on their left operand, with their right operand self-determined. Get the handling of these operators out of the PEBinary base class to prevent confusion. --- PExpr.cc | 20 +++++++++++- PExpr.h | 47 +++++++++++++++++++++++----- elab_expr.cc | 86 +++++++++++++++++++++++++++++++++++++++++---------- elab_pexpr.cc | 14 +++++++++ netmisc.cc | 1 + parse.y | 2 +- 6 files changed, 145 insertions(+), 25 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index 7ee5f9298..f375515b2 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -95,11 +95,29 @@ PEBLogic::~PEBLogic() { } -PEBShift::PEBShift(char op, PExpr*l, PExpr*r) +PEBLeftWidth::PEBLeftWidth(char op, PExpr*l, PExpr*r) : PEBinary(op, l, r) { } +PEBLeftWidth::~PEBLeftWidth() +{ +} + +PEBPower::PEBPower(char op, PExpr*l, PExpr*r) +: PEBLeftWidth(op, l, r) +{ +} + +PEBPower::~PEBPower() +{ +} + +PEBShift::PEBShift(char op, PExpr*l, PExpr*r) +: PEBLeftWidth(op, l, r) +{ +} + PEBShift::~PEBShift() { } diff --git a/PExpr.h b/PExpr.h index e043da23a..f37928556 100644 --- a/PExpr.h +++ b/PExpr.h @@ -535,18 +535,51 @@ class PEBLogic : public PEBinary { NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; }; -class PEBShift : public PEBinary { +/* + * A couple of the binary operands have a special sub-expression rule + * where the expression width is carried entirely by the left + * expression, and the right operand is self-determined. + */ +class PEBLeftWidth : public PEBinary { + + public: + explicit PEBLeftWidth(char op, PExpr*l, PExpr*r); + ~PEBLeftWidth() =0; + + virtual NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp, + int expr_wid) const =0; + + protected: + virtual unsigned test_width(Design*des, NetScope*scope, + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&flag); + + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + int expr_width, bool sys_task_arg) const; + + virtual NetExpr*elaborate_pexpr(Design*des, NetScope*scope) const; + +}; + +class PEBPower : public PEBLeftWidth { + + public: + explicit PEBPower(char op, PExpr*l, PExpr*r); + ~PEBPower(); + + NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp, + int expr_wid) const; +}; + +class PEBShift : public PEBLeftWidth { public: explicit PEBShift(char op, PExpr*l, PExpr*r); ~PEBShift(); - virtual unsigned test_width(Design*des, NetScope*scope, - unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, - bool&flag); - virtual NetExpr*elaborate_expr(Design*des, NetScope*, - int expr_width, bool sys_task_arg) const; + NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp, + int expr_wid) const; }; /* diff --git a/elab_expr.cc b/elab_expr.cc index 2e6fba336..fcd77e76c 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -177,6 +177,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, case 'G': // >= Should be handled by PEBComp case 'n': // != Should be handled by PEBComp case 'N': // !== Should be handled by PEBComp + case 'p': // ** should be handled by PEBPower ivl_assert(*this, 0); default: if (wid_left > min) @@ -315,14 +316,15 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des, tmp = elaborate_expr_base_div_(des, lp, rp, expr_wid); break; - case 'l': // << - tmp = elaborate_expr_base_lshift_(des, lp, rp, expr_wid); - break; - - case 'r': // >> - case 'R': // >>> - tmp = elaborate_expr_base_rshift_(des, lp, rp, expr_wid); - break; + case 'l': + case 'r': + case 'R': + cerr << get_fileline() << ": internal error: " + << "Elaboration of " << human_readable_op(op_) + << " Should have been handled in NetEBShift::elaborate." + << endl; + des->errors += 1; + return 0; case '^': case '&': @@ -861,12 +863,12 @@ NetExpr*PEBLogic::elaborate_expr(Design*des, NetScope*scope, return tmp; } -unsigned PEBShift::test_width(Design*des, NetScope*scope, +unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, ivl_variable_type_t&expr_type__, bool&unsized_flag) { - unsigned wid_left = left_->test_width(des,scope,min, 0, expr_type__, unsized_flag); + unsigned wid_left = left_->test_width(des,scope,min, lval, expr_type__, unsized_flag); // The right expression is self-determined and has no impact // on the expression size that is generated. @@ -876,12 +878,15 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope, if (wid_left < lval) wid_left = lval; - if (unsized_flag && wid_left < integer_width) { + if (unsized_flag + && type_is_vectorable(expr_type__) + && wid_left > 0 + && wid_left < integer_width) { wid_left = integer_width; if (debug_elaborate) cerr << get_fileline() << ": debug: " - << "Test width of unsized left shift" + << "Test width of unsized " << human_readable_op(op_) << " is padded to compiler integer width=" << wid_left << endl; } @@ -897,20 +902,28 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope, unsigned wid_right = right_->test_width(des, scope, 0, 0, rtype, rflag); if (debug_elaborate) cerr << get_fileline() << ": debug: " - << "Test width of shift amount of shift expression " + << "Test width of exponent of " << op_ << " expression " << "returns wid=" << wid_right << ", type=" << rtype << ", flag=" << rflag << endl; return expr_width_; } -NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope, - int expr_wid, bool sys_task_arg) const +NetExpr*PEBLeftWidth::elaborate_expr(Design*des, NetScope*scope, + int expr_wid, bool sys_task_arg) const { assert(left_); assert(right_); NetExpr*lp = left_->elaborate_expr(des, scope, expr_wid, false); + if (expr_wid > 0 && lp->expr_width() < (unsigned)expr_wid) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Pad left operand of " << human_readable_op(op_) + << " to " << expr_wid << "." << endl; + lp = pad_to_width(lp, expr_wid, *this); + } + NetExpr*rp = right_->elaborate_expr(des, scope, -1, false); if ((lp == 0) || (rp == 0)) { delete lp; @@ -918,7 +931,48 @@ NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope, return 0; } - NetExpr*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid); + eval_expr(lp); + eval_expr(rp); + + return elaborate_expr_leaf(des, lp, rp, expr_wid); +} + +NetExpr*PEBPower::elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp, + int expr_wid) const +{ + if (debug_elaborate) { + cerr << get_fileline() << ": debug: elaborate expression " + << *this << " expr_wid=" << expr_wid << endl; + } + + NetExpr*tmp = new NetEBPow(op_, lp, rp); + tmp->set_line(*this); + + return tmp; +} + +NetExpr*PEBShift::elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp, + int expr_wid) const +{ + NetExpr*tmp = 0; + + switch (op_) { + case 'l': + tmp = elaborate_expr_base_lshift_(des, lp, rp, expr_wid); + break; + + case 'r': // >> + case 'R': // >>> + tmp = elaborate_expr_base_rshift_(des, lp, rp, expr_wid); + break; + + default: + cerr << get_fileline() << ": internal error: " + << "Unexpected opcode " << human_readable_op(op_) + << " in PEBShift::elaborate_expr_leaf." << endl; + des->errors += 1; + } + return tmp; } diff --git a/elab_pexpr.cc b/elab_pexpr.cc index a8728cafc..e30eaac64 100644 --- a/elab_pexpr.cc +++ b/elab_pexpr.cc @@ -81,6 +81,20 @@ NetExpr*PEBComp::elaborate_pexpr(Design*des, NetScope*scope) const return tmp; } +NetExpr*PEBLeftWidth::elaborate_pexpr (Design*des, NetScope*scope) const +{ + NetExpr*lp = left_->elaborate_pexpr(des, scope); + NetExpr*rp = right_->elaborate_pexpr(des, scope); + if ((lp == 0) || (rp == 0)) { + delete lp; + delete rp; + return 0; + } + + NetExpr*tmp = elaborate_expr_leaf(des, lp, rp, -2); + return tmp; +} + NetExpr*PEBLogic::elaborate_pexpr(Design*des, NetScope*scope) const { NetExpr*lp = left_->elaborate_pexpr(des, scope); diff --git a/netmisc.cc b/netmisc.cc index 54faac2f7..4223a0399 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -405,6 +405,7 @@ const char *human_readable_op(const char op) case 'r': type = ">>"; break; // Logical right shift case 'R': type = ">>>"; break; // Arithmetic right shift + case 'p': type = "**"; break; // Power default: assert(0); } diff --git a/parse.y b/parse.y index 32d281b12..b78e8318c 100644 --- a/parse.y +++ b/parse.y @@ -929,7 +929,7 @@ expression $$ = tmp; } | expression K_POW expression - { PEBinary*tmp = new PEBinary('p', $1, $3); + { PEBinary*tmp = new PEBPower('p', $1, $3); FILE_NAME(tmp, @2); $$ = tmp; }